一、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) 首先對錶進行分析:
ANALYZE TABLE <tablename> ESTIMATE/COMPUTE STATISTICS;
b) SELECT blocks, empty_blocks, num_rows
FROM user_tables
WHERE table_name = <tablename>;
說明:
BLOCKS
列代表該表中曾經使用過得資料庫塊的數目,即水線。
EMPTY_BLOCKS
代表分配給該表,但是在水線以上的資料庫塊,即從來沒有使用的資料塊。
讓我們以一個有28672行的BIG_EMP1
表為例進行說明:
SQL> SELECT segment_name, segment_type, blocks
FROM dba_segments
WHERE segment_name='BIG_EMP1';
SEGMENT_NAME SEGMENT_TYPE BLOCKS
----------------- -------------- ---------
BIG_EMP1 TABLE 1024
1 row selected.
SQL> ANALYZE TABLE big_emp1 ESTIMATE STATISTICS;
Statement processed.
SQL> SELECT table_name,num_rows,blocks,empty_blocks
FROM user_tables
WHERE table_name='BIG_EMP1';
TABLE_NAME NUM_ROWS BLOCKS EMPTY_BLOCKS
---------- -------- ------- -------------
BIG_EMP1 28672 700 323
1 row selected.
注意:
BLOCKS + EMPTY_BLOCKS (700+323=1023)比DBA_SEGMENTS.BLOCKS
少1個數據庫塊,這是因為有一個數據庫塊被保留用作segment header
。DBA_SEGMENTS.BLOCKS
表示分配給這個表的所有的資料庫塊的數目。USER_TABLES.BLOCKS
表示已經使用過的資料庫塊的數目。
SQL> SELECT COUNT (DISTINCT
DBMS_ROWID.ROWID_BLOCK_NUMBER(rowid)||
DBMS_ROWID.ROWID_RELATIVE_FNO(rowid)) "Used"
FROM big_emp1;
Used
----------
700
1 row selected.
SQL> delete from big_emp1;
28672 rows processed.
SQL> commit;
Statement processed.
SQL> ANALYZE TABLE big_emp1 ESTIMATE STATISTICS;
Statement processed.
SQL> SELECT table_name,num_rows,blocks,empty_blocks
FROM user_tables
WHERE table_name='BIG_EMP1';
TABLE_NAME NUM_ROWS BLOCKS EMPTY_BLOCKS
--------- -------- ------- ----------
BIG_EMP1 0 700 323
1 row selected.
SQL> SELECT COUNT (DISTINCT
DBMS_ROWID.ROWID_BLOCK_NUMBER(rowid)||
DBMS_ROWID.ROWID_RELATIVE_FNO(rowid)) "Used"
FROM big_emp1;
Used
----------
0 ----這表名沒有任何資料庫塊容納資料,即表中無資料
1 row selected.
SQL> TRUNCATE TABLE big_emp1;
Statement processed.
SQL> ANALYZE TABLE big_emp1 ESTIMATE STATISTICS;
Statement processed.
SQL> SELECT table_name,num_rows,blocks,empty_blocks
2> FROM user_tables
3> WHERE table_name='BIG_EMP1';
TABLE_NAME NUM_ROWS BLOCKS EMPTY_BLOCKS
---------- -------- -------- ------------
BIG_EMP1 0 0 511
1 row selected.
SQL> SELECT segment_name,segment_type,blocks
FROM dba_segments
WHERE segment_name='BIG_EMP1';
SEGMENT_NAME SEGMENT_TYPE BLOCKS
------------ ------------- ------
BIG_EMP1 TABLE 512
1 row selected.
注意:
TRUNCATE
命令回收了由delete
命令產生的空閒空間,注意該表分配的空間由原先的1024塊降為512塊。
為了保留由delete
命令產生的空閒空間,可以使用TRUNCATE TABLE big_emp1 REUSE STORAGE
.
用此命令後,該表還會是原先的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
,但是在Oracle9i Release1
才新增的自動段空間管理(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;
3.複製要保留的資料到臨時表t,drop
原表,然後rename
臨時表t為原表
4.emp/imp
5.alter table table_name deallocate unused
6.儘量truncate
吧