深入瞭解oracle的高水位(HWM)
(1)塊:是粒度最小的儲存單位,現在標準的塊大小是8K,ORACLE每一次I/O操作也是按塊來操作的,也就是說當ORACLE從資料檔案讀資料時,是讀取多少個塊,而不是多少行.
(2)區:由一系列相鄰的塊而組成,這也是ORACLE空間分配的基本單位,舉個例子來說,當我們建立一個表PM_USER時,首先ORACLE會分配一區的空間給這個表,隨著不斷的INSERT資料到PM_USER,原來的這個區容不下插入的資料時,ORACLE是以區為單位進行擴充套件的,也就是說再分配多少個區給PM_USER,而不是多少個塊.
(3)段:是由一系列的區所組成,一般來說,當建立一個物件時(表,索引),就會分配一個段給這個物件.所以從某種意義上來說,段就是某種特定的資料.如CREATE TABLE PM_USER,這個段就是資料段,而CREATE INDEX ON PM_USER(NAME),ORACLE同樣會分配一個段給這個索引,但這是一個索引段了.查詢段的資訊可以透過資料字典: SELECT * FROM USER_SEGMENTS來獲得,
(4)表空間:包含段,區及塊.表空間的資料物理上儲存在其所在的資料檔案中.一個資料庫至少要有一個表空間.
OK,我們現在回到HWM上來,那麼,什麼是高水位標記呢?這就跟ORACLE的段空間管理相關了.
(一)ORACLE用HWM來界定一個段中使用的塊和未使用的塊.
舉個例子來說,當我們建立一個表:PT_SCHE_DETAIL時,ORACLE就會為這個物件分配一個段.在這個段中,即使我們未插入任何記錄,也至少有一個區被分配,第一個區的第一個塊就稱為段頭(SEGMENT HEADE),段頭中就儲存了一些資訊,基中HWM的資訊就儲存在此.此時,因為第一個區的第一塊用於儲存段頭的一些資訊,雖然沒有儲存任何實際的記錄,但也算是被使用,此時HWM是位於第2個塊.當我們不斷插入資料到PM_USER後,第1個塊已經放不下後面新插入的資料,此時,ORACLE將高水位之上的塊用於新增資料,同時,HWM本身也向上移.也就是說,當我們不斷插入資料時,HWM會往不斷上移,這樣,在HWM之下的,就表示使用過的塊,HWM之上的就表示已分配但從未使用過的塊.
(二)HWM在插入資料時,當現有空間不足而進行空間的擴充套件時會向上移,但刪除時不會往下移.
這就好比是水庫的水位,當漲水時,水位往上移,當水退出後,最高水位的痕跡還是清淅可見.
考慮讓我們看一個段,如一張表,其中填滿了塊,如圖 1 所示。在正常操作過程中,刪除了一些行,如圖 2 所示。現有就有了許多浪費的空間:(I) 在表的上一個末端和現有的塊之間,以及 (II) 在塊內部,其中還有一些沒有刪除的行。
圖" 1:分配給該表的塊。用灰色正方形表示行
ORACLE 不會釋放空間以供其他物件使用,有一條簡單的理由:由於空間是為新插入的行保留的,並且要適應現有行的增長。被佔用的最高空間稱為最高使用標記 (HWM),如圖 2 所示。
圖" 2:行後面的塊已經刪除了;HWM 仍保持不變
(三)HWM的資訊儲存在段頭當中.
HWM本身的資訊是儲存在段頭.在段空間是手工管理方式時,ORACLE是透過FREELIST(一個單向連結串列)來管理段內的空間分配.在段空間是自動管理方式時(ASSM),ORACLE是透過BITMAP來管理段內的空間分配.
(四)ORACLE的全表掃描是讀取高標記(HWM)以下的所有塊.
所以問題就產生了(一直不解為何ORACLE會採用這種不合理的方式).當使用者發出一個全表掃描時,ORACLE 始終必須從段一直掃描到 HWM,即使它什麼也沒有發現。該任務延長了全表掃描的時間。
(五)當用直接路徑插入行時 — 例如,透過直接載入插入(用 APPEND 提示插入)或透過 SQL*LOADER 直接路徑 — 資料塊直接置於 HWM 之上。它下面的空間就浪費掉了。
我們來分析這兩個問題,後者只是帶來空間的浪費,但前者不僅是空間的浪費,而且會帶來嚴重的效能問題.我們來看看下面的例子:
(A)我們先來搭建測試的環境,第一步先建立一個段為手工管理的:
CREATE TABLESPACE "RAINNY"
LOGGING
DATAFILE 'D:ORACLE_HOMEORADATARAINNYRAINNY.ORA' SIZE 5M
AUTOEXTEND
ON NEXT 10M MAXSIZE UNLIMITED EXTENT MANAGEMENT LOCAL
SEGMENT SPACE MANAGEMENT MANUAL;
(B)建立一個表,注意,此表的第二個欄位我故意設成是CHAR(100),以讓此表在插入1千萬條記錄後,空間有足夠大:
CREATE TABLE TEST_TAB(C1 NUMBER(10),C2 CHAR(100)) TABLESPACE RAINNY;
插入記錄DECLARE
I NUMBER(10);BEGIN
FOR I IN 1..10000000 LOOP
INSERT INTO TEST_TAB VALUES(I,'TESTSTRING');
END LOOP;
COMMIT;END ;
(C)我們來查詢一下,看在插入一千萬條記錄後所訪問的塊數和查詢所用時間:
SQL> SET TIMING ON
SQL> SET AUTOTRACE TRACEONLY
SQL> SELECT COUNT(*) FROM TEST_TAB;
ELAPSED: 00:01:03.05
EXECUTION PLAN
----------------------------------------------------------
0 SELECT STATEMENT OPTIMIZER=CHOOSE (COST=15056 CARD=1)
1 0 SORT (AGGREGATE)
2 1 TABLE ACCESS (FULL) OF 'TEST_TAB' (COST=15056 CARD=10000
000)
STATISTICS
----------------------------------------------------------
0 RECURSIVE CALLS
0 DB BLOCK GETS
156310 CONSISTENT GETS
154239 PHYSICAL READS
0 REDO SIZE
379 BYTES SENT VIA SQL*NET TO CLIENT
503 BYTES RECEIVED VIA SQL*NET FROM CLIENT
2 SQL*NET ROUNDTRIPS TO/FROM CLIENT
0 SORTS (MEMORY)
0 SORTS (DISK)
1 ROWS PROCESSED
SQL>
我們來看上面的執行計劃,這句SQL總供耗時是:1分3秒.訪問方式是採用全表掃描方式(FTS),邏輯讀了156310個BLOCK,物理讀了154239個BLOCK.
我們來分析一下這個表:
BEGIN
DBMS_STATS.GATHER_TABLE_STATS(OWNNAME=> 'TEST',
TABNAME=> 'TEST_TAB',
PARTNAME=> NULL);END;
發現這個表目前使用的BLOCK有: 156532,未使用的BLOCK(EMPTY_BLOCKS)為:0,總行數為(NUM_ROWS):1000 0000
(D)接下來我們把此表的記錄用DELETE方式刪掉,然後再來看看SELECT COUNT(*) FROM TEST_TAB所花的時間:
DELETE FROM TEST_TAB;
COMMIT;
SQL> SELECT COUNT(*) FROM TEST_TAB;
ELAPSED: 00:01:04.03
EXECUTION PLAN
----------------------------------------------------------
0 SELECT STATEMENT OPTIMIZER=CHOOSE (COST=15056 CARD=1)
1 0 SORT (AGGREGATE)
2 1 TABLE ACCESS (FULL) OF 'TEST_TAB' (COST=15056 CARD=1)
STATISTICS
----------------------------------------------------------
0 RECURSIVE CALLS
0 DB BLOCK GETS
156310 CONSISTENT GETS
155565 PHYSICAL READS
0 REDO SIZE
378 BYTES SENT VIA SQL*NET TO CLIENT
503 BYTES RECEIVED VIA SQL*NET FROM CLIENT
2 SQL*NET ROUNDTRIPS TO/FROM CLIENT
0 SORTS (MEMORY)
0 SORTS (DISK)
1 ROWS PROCESSED
SQL>
大家來看,在DELETE表後,此時表中已沒有一條記錄,為什麼SELECT COUNT(*) FROM TEST_TAB花的時間為1分4秒,
來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/35489/viewspace-84772/,如需轉載,請註明出處,否則將追究法律責任。
相關文章
- ORACLE 高水位線(HWM)Oracle
- Oracle案例10——HWM(高水位線)效能優化Oracle優化
- 一、oracle 高水位線詳解Oracle
- oracle 高水位分析處理Oracle
- oracle高水位線處理Oracle
- ORACLE FREELIST HWM(轉)Oracle
- ORACLE資料庫降低高水位線方法Oracle資料庫
- ORACLE 如何診斷高水位爭用(enq: HW – contention)OracleENQ
- Oracle 高水位查詢和處理方法彙總Oracle
- 深入瞭解MySQL的索引MySql索引
- 關於高水位的知識
- 深入瞭解原型原型
- 深入瞭解ConcurrentHashMapHashMap
- JavaScript——深入瞭解thisJavaScript
- Oracle資料庫管理——表資料庫高水位及shrink操作Oracle資料庫
- 深入瞭解JavaScript中的物件JavaScript物件
- 深入瞭解babel(一)Babel
- [譯] 深入瞭解 FlutterFlutter
- 深入瞭解Synchronized原理synchronized
- 深入瞭解SCN(轉)
- Oracle資料庫高水位釋放——LOB欄位空間釋放Oracle資料庫
- 深入瞭解 iOS 的初始化iOS
- 深入瞭解解析Https - 從瞭解到放棄HTTP
- 深入瞭解Object.definePropertyObject
- 深入瞭解 Object.definePropertyObject
- 深入瞭解 Builder 模式 - frankelUI模式
- 深入瞭解Zookeeper核心原理
- 深入瞭解 Java 的 volatile 關鍵字Java
- Java——深入瞭解Java中的迭代器Java
- 深入瞭解gradle和maven的區別GradleMaven
- 前端進階-深入瞭解物件前端物件
- Nginx深入瞭解-基礎(一)Nginx
- Nginx深入瞭解-基礎(三)Nginx
- 深入瞭解機器學習機器學習
- 深入瞭解SpringMVC原始碼解析SpringMVC原始碼
- Oracle move和shrink釋放高水位空間Oracle
- 從基礎到高階,帶你深入瞭解和使用curl命令(二)
- 深入瞭解最新的Vue Devtools v5.0Vuedev
- 深入瞭解Kubernetes REST API的工作方式RESTAPI