高水位線基礎
一、oracle 高水位線詳解
一、什麽是水線(High Water Mark)?
所有的oracle 段(segments,在此,為了理解方便,建議把segment 作為表的一個同義詞) 都
有一個在段內容納數據的上限,我們把這個上限稱為"high water mark"或HWM。這個HWM
是一個標記,用來說明已經有多少沒有使用的數據塊分配給這個segment。HWM 通常增長的
幅度為一次5個數據塊,原則上HWM 只會增大,不會縮小,即使將表中的數據全部刪除,HWM
還是為原值,由於這個特點,使HWM 很象一個水庫的歷史最高水位,這也就是HWM 的原始含
義,當然不能說一個水庫沒水了,就說該水庫的歷史最高水位為0。但是如果我們在表上使
用了truncate 命令,則該表的HWM 會被重新置為0。
二、HWM 數據庫的操作有如下影響:
a) 全表掃描通常要讀出直到HWM 標記的所有的屬於該表數據庫塊,即使該表中沒有任何數
據。
b) 即使HWM 以下有空閑的數據庫塊,鍵入在插入數據時使用了append 關鍵字,則在插入時
使用HWM 以上的數據塊,此時HWM 會自動增大。
三、如何知道一個表的HWM?
a) 首先對表進行分析:
1 ANALYZE TABLE <tablename> ESTIMATE/COMPUTE STATISTICS;
b)
1 SELECT blocks, empty_blocks, num_rows FROM user_tables WHERE table_name = <tablename>;
說明:
BLOCKS 列代表該表中曾經使用過得數據庫塊的數目,即水線。
EMPTY_BLOCKS 代表分配給該表,但是在水線以上的數據庫塊,即從來沒有使用的數據塊。
讓我們以一個有28672行的BIG_EMP1表為例進行說明:
1 1) SQL> SELECT segment_name, segment_type, blocks FROM dba_segments WHERE segment_name=‘BIG_EMP1‘; 2 SEGMENT_NAME SEGMENT_TYPE BLOCKS 3 ----------------- -------------- ---------4 BIG_EMP1 TABLE 1024 5 1 row selected. 6 7 2) SQL> ANALYZE TABLE big_emp1 ESTIMATE STATISTICS; 8 9 Statement processed. 10 11 3) SQL> SELECT table_name,num_rows,blocks,empty_blocks FROM user_tables WHERE table_name=‘BIG_EMP1‘; 12 TABLE_NAME NUM_ROWS BLOCKS EMPTY_BLOCKS 13 ---------- -------- ------- ------------- 14 BIG_EMP1 28672 700 323 15 1 row selected. 16 --註意: 17 /*BLOCKS + EMPTY_BLOCKS (700+323=1023)比DBA_SEGMENTS.BLOCKS 少1個數據庫塊,這是因 18 為有一個數據庫塊被保留用作segment header。DBA_SEGMENTS.BLOCKS 表示分配給這個表 19 的所有的數據庫塊的數目。USER_TABLES.BLOCKS 表示已經使用過的數據庫塊的數目。*/ 20 4) SQL> SELECT COUNT (DISTINCT DBMS_ROWID.ROWID_BLOCK_NUMBER(rowid)|| DBMS_ROWID.ROWID_RELATIVE_FNO(rowid)) "Used" FROM big_emp1; 21 Used 22 ---------- 23 700 24 1 row selected. 25 26 5) SQL> delete from big_emp1; 27 28 28672 rows processed. 29 30 6) SQL> commit; 31 32 Statement processed. 33 34 7) SQL> ANALYZE TABLE big_emp1 ESTIMATE STATISTICS; 35 36 Statement processed. 37 38 8) SQL> SELECT table_name,num_rows,blocks,empty_blocks FROM user_tables WHERE table_name=‘BIG_EMP1‘; 39 40 TABLE_NAME NUM_ROWS BLOCKS EMPTY_BLOCKS 41 --------- -------- ------- ---------- 42 BIG_EMP1 0 700 323 43 1 row selected. 44 45 9) SQL> SELECT COUNT (DISTINCT DBMS_ROWID.ROWID_BLOCK_NUMBER(rowid)|| DBMS_ROWID.ROWID_RELATIVE_FNO(rowid)) "Used" FROM big_emp1; 46 Used 47 ---------- 48 /* 49 0 ----這表名沒有任何數據庫塊容納數據,即表中無數據 */ 50 1 row selected. 51 10) SQL> TRUNCATE TABLE big_emp1; 52 Statement processed. 53 11) SQL> ANALYZE TABLE big_emp1 ESTIMATE STATISTICS; 54 Statement processed. 55 12) SQL> SELECT table_name,num_rows,blocks,empty_blocks 56 2> FROM user_tables 57 3> WHERE table_name=‘BIG_EMP1‘; 58 TABLE_NAME NUM_ROWS BLOCKS EMPTY_BLOCKS 59 ---------- -------- -------- ------------ 60 BIG_EMP1 0 0 511 61 1 row selected. 62 13) SQL> SELECT segment_name,segment_type,blocks 63 FROM dba_segments 64 WHERE segment_name=‘BIG_EMP1‘; 65 SEGMENT_NAME SEGMENT_TYPE BLOCKS 66 ------------ ------------- ------ 67 BIG_EMP1 TABLE 512 68 1 row selected. 69 /* 70 註意: 71 TRUNCATE 命令回收了由delete 命令產生的空閑空間,註意該表分配的空間由原先的1024塊 72 降為512塊。 73 為了保留由delete 命令產生的空閑空間,可以使用TRUNCATE TABLE big_emp1 REUSE 74 STORAGE. 75 用此命令後,該表還會是原先的1024塊。*/
四、Oracle 表段中的高水位線HWM
在Oracle 數據的存儲中,可以把存儲空間想象為一個水庫,數據想象為水庫中的水。水庫
中的水的位置有一條線叫做水位線,在Oracle 中,這條線被稱為高水位線(High-warter mark,
HWM)。在數據庫表剛建立的時候,由於沒有任何數據,所以這個時候水位線是空的,也就是
說HWM 為最低值。當插入了數據以後,高水位線就會上漲,但是這裏也有一個特性,就是如
果你采用delete 語句刪除數據的話,數據雖然被刪除了,但是高水位線卻沒有降低,還是
你剛才刪除數據以前那麽高的水位。也就是說,這條高水位線在日常的增刪操作中只會上漲,
不會下跌。
下面我們來談一下Oracle 中Select 語句的特性。Select 語句會對表中的數據進行一次掃
描,但是究竟掃描多少數據存儲塊呢,這個並不是說數據庫中有多少數據,Oracle 就掃描
這麽大的數據塊,而是Oracle 會掃描高水位線以下的數據塊。現在來想象一下,如果剛才
是一張剛剛建立的空表,你進行了一次Select 操作,那麽由於高水位線HWM 在最低的0位置
上,所以沒有數據塊需要被掃描,掃描時間會極短。而如果這個時候你首先插入了一千萬條
數據,然後再用delete 語句刪除這一千萬條數據。由於插入了一千萬條數據,所以這個時
候的高水位線就在一千萬條數據這裏。後來刪除這一千萬條數據的時候,由於delete 語句
不影響高水位線,所以高水位線依然在一千萬條數據這裏。這個時候再一次用select 語句
進行掃描,雖然這個時候表中沒有數據,但是由於掃描是按照高水位線來的,所以需要把一
千萬條數據的存儲空間都要掃描一次,也就是說這次掃描所需要的時間和掃描一千萬條數據
所需要的時間是一樣多的。所以有時候有人總是經常說,怎麽我的表中沒有幾條數據,但是
還是這麽慢呢,這個時候其實奧秘就是這裏的高水位線了。
那有沒有辦法讓高水位線下降呢,其實有一種比較簡單的方法,那就是采用TRUNCATE 語句
進行刪除數據。采用TRUNCATE 語句刪除一個表的數據的時候,類似於重新建立了表,不僅
把數據都刪除了,還把HWM 給清空恢復為0。所以如果需要把表清空,在有可能利用TRUNCATE
語句來刪除數據的時候就利用TRUNCATE 語句來刪除表,特別是那種數據量有可能很大的臨
時存儲表。
在手動段空間管理(Manual Segment Space Management)中,段中只有一個HWM,但是在
Oracle9iRelease1才添加的自動段空間管理(Automatic Segment Space Management)中,
又有了一個低HWM 的概念出來。為什麽有了HWM 還又有一個低HWM 呢,這個是因為自動段空
間管理的特性造成的。在手段段空間管理中,當數據插入以後,如果是插入到新的數據塊中,
數據塊就會被自動格式化等待數據訪問。而在自動段空間管理中,數據插入到新的數據塊以
後,數據塊並沒有被格式化,而是在第一次在第一次訪問這個數據塊的時候才格式化這個塊。
所以我們又需要一條水位線,用來標示已經被格式化的塊。這條水位線就叫做低HWM。一般
來說,低HWM 肯定是低於等於HWM 的。
五、修正ORACLE 表的高水位線
在ORACLE 中,執行對表的刪除操作不會降低該表的高水位線。而全表掃描將始終讀取一個
段(extent)中所有低於高水位線標記的塊。如果在執行刪除操作後不降低高水位線標記,則
將導致查詢語句的性能低下。下面的方法都可以降低高水位線標記。
1.執行表重建指令alter table table_name move;
(在線轉移表空間ALTER TABLE 。。。MOVE TABLESPACE 。。。ALTER TABLE 。。。MOVE 後面
不跟參數也行,不跟參數表還是在原來的表空間,move 後記住重建索引。如果以後還要繼
續向這個表增加數據,沒有必要move,只是釋放出來的空間,只能這個表用,其他的表或
者segment 無法使用該空間)
2.執行alter table table_name shrink space;
註意,此命令為Oracle 10g 新增功能,
再執行該指令之前必須允許行移動alter table table_name enable row movement;
實質上構造一個新表(在內部表現為一系列的DML 操作,即將副本插入新位置,刪除原來位
置的記錄)靠近末尾處(右端)數據塊中的記錄往開始處(左端)的空閑空間處移動(DML 操作),
不會引起DML 觸發器
當所有可能的移動被完成,高水位線將會往左端移動(DDL 操作)
;新的高水位線右邊的空閑空間被釋放(DDL 操作);
實現前提條件
必須啟用行記錄轉移(enable row movement)
僅僅適用於堆表,且位於自動段空間管理的表空間(堆表包括:標準表,分區表,物化視圖容器,
物化視圖日誌表)
3.復制要保留的數據到臨時表t,drop 原表,然後rename 臨時表t 為原表
4.emp/imp
5.alter table table_name deallocate unused
6.盡量truncate 吧
高水位線基礎