Oracle 之HWM

靜以致遠√團團發表於2014-07-28

Oracle HWM

什麼是HWM

所有的oracle segments都有一個在段內容納資料的上限,我們把這個上限稱為HWM(High Water Mark)。這個HWM是一個標記,用來說明已經有多少沒有使用的資料塊分配給這個segment。HWM通常增長的幅度為一次5個資料塊,原則上HWM只會增大,不會縮小,即使將表中的資料全部刪除,HWM還是為原值,由於這個特點,使HWM很象一個水庫的歷史最高水位,這也就是HWM的原始含義,當然不能說一個水庫沒水了,就說該水庫的歷史最高水位為0。但是如果我們在表上使用了truncate命令,則該表的HWM會被重新置為0。

在手動段空間管理(Manual Segment Space Management)中,段中只有一個HWM,但是在Oracle9i新增的自動段空間管理(Automatic Segment Space Management)中,當資料插入以後,如果是插入到新的資料塊中,資料塊就會被自動格式化等待資料訪問。而在自動段空間管理中,資料插入到新的資料塊以後,資料塊並沒有被格式化,而是在第一次在第一次訪問這個資料塊的時候才格式化這個塊。所以又多出一條水位線,用來標示已經被格式化的塊。這條水位線就叫做低HWM。一般來說,低HWM肯定是低於等於HWM。

HWM的影響

HWM的用途

在使用select語句會對錶中的資料進行一次掃描,Oracle會掃描高水位線以下的資料塊。也就是說新建的一張表,進行了一次select操作,那麼由於高水位線HWM在最低的0位置上,所以沒有資料塊需要被掃描,掃描時間會極短。如果該表中已經被插入大量的資料,隨後這些資料被delete。由於插入了資料,由於delete語句不影響高水位線,所以這個時候的高水位線就在這些資料這裡。這個時候再一次用select語句進行掃描,雖然這個時候表中沒有資料,但是由於掃描是按照高水位線來的,需要把這些資料的儲存空間都要掃描一次。 HWM資料庫的操作有如下影響

1、全表掃描通常要讀出直到HWM標記的所有的屬於該表資料庫塊,即使該表中沒有任何資料。

2、即使HWM以下有空閒的資料庫塊,鍵入在插入資料時使用了append關鍵字,則在插入時使用HWM以上的資料塊,此時HWM會自動增大。

測試一下

建立一個測試表

SQL> create table test(id number(4,0),test varchar2(10)) tablespace users;

Table created.

此時表中沒有資料,透過user_tables和user_segments來檢視一下表中資料塊的使用情況

SQL> col segment_name for a20

SQL> select segment_name,segment_type,blocks,bytes from user_segments where segment_name='TEST';


SEGMENT_NAME         SEGMENT_TYPE           BLOCKS      BYTES

-------------------- ------------------ ---------- ----------

TEST                 TABLE                       8      65536

這裡的BLOCKS指的是該表初始化segment的大小


使用analyze 收集統計資訊


SQL> analyze table test compute statistics;

Table analyzed.

SQL> select table_name,num_rows,blocks,empty_blocks from user_tables where table_name='TEST';


TABLE_NAME        NUM_ROWS     BLOCKS EMPTY_BLOCKS

--------------- ---------- ---------- ------------

TEST                     0          0            8

也就是說現在分給給test表的8個資料庫都處於空閒狀態

插入測試資料

SQL> begin

2  for i in 1..10000 loop

3  insert into test

4  values(round(dbms_random.value(0,10000)),dbms_random.string('u',5));

5  end loop;

6  commit;

7  end;

8  /


PL/SQL procedure successfully completed.

SQL> select count(*) from test;

COUNT(*)

----------

10000


再次檢視此時的segment分配資訊,已經非配32個block

SQL> select segment_name,segment_type,blocks from user_segments where segment_name='TEST';


SEGMENT_NAME         SEGMENT_TYPE           BLOCKS

-------------------- ------------------ ----------

TEST                 TABLE                      32


SQL> analyze table test compute statistics;

Table analyzed.


SQL> select table_name,blocks,empty_blocks from user_tables where table_name='TEST';

TABLE_NAME          BLOCKS EMPTY_BLOCKS

--------------- ---------- ------------

TEST                    28            4

segment和tables中的block對應關係如下

user_segment.blocks=user_tables.blocks+user_tables.empty_blocks+1

其中

user_tables.blocks列代表該表中曾經使用過得資料庫塊的數目,即水線。 

user_tables.empty_blocks代表分配給該表,但是在水線以上的資料庫塊,即從來沒有使用的資料塊。

1是指多出的一個資料塊用保留來做segment header

使用delete 刪除表中資料,將會發現表中資料的水線並未降低

SQL> delete from test;

10000 rows deleted.


SQL> commit;

Commit complete.


SQL> select segment_name,segment_type,blocks from user_segments where segment_name='TEST';


SEGMENT_NAME         SEGMENT_TYPE           BLOCKS

-------------------- ------------------ ----------

TEST                 TABLE                      32


SQL> analyze table test compute statistics;

Table analyzed.


SQL> select table_name,blocks,empty_blocks from user_tables where table_name='TEST';

TABLE_NAME          BLOCKS EMPTY_BLOCKS

--------------- ---------- ------------

TEST                    28            4


使用shrink收縮表

SQL> alter table test enable row movement;

Table altered.


SQL> alter table test shrink space cascade;

Table altered.


SQL> select segment_name,segment_type,blocks from user_segments where segment_name='TEST';


SEGMENT_NAME         SEGMENT_TYPE           BLOCKS

-------------------- ------------------ ----------

TEST                 TABLE                       8


SQL> analyze table test compute statistics;


Table analyzed.


SQL> select table_name,blocks,empty_blocks from user_tables where table_name='TEST';


TABLE_NAME          BLOCKS EMPTY_BLOCKS

--------------- ---------- ------------

TEST                     1            7


回收HWM

1、使用move移動表

SQL> alter table test move;


Table altered.


SQL> alter table test move tablespace users;

Table altered.

2、如上面測試中的方法,使用shrink來收縮表

3、可以的情況下重建表 

4、使用alter  table table_name deallocate unused

DEALLOCATE UNUSED為釋放HWM上面的未使用空間,但是並不會釋放HWM下面的自由空間,也不會移動HWM的位置.

5、不重要的資料被刪除,或者確定該表中資料不需要閃回的情況下儘量使用truncate刪除資料。



來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/29320885/viewspace-1240343/,如需轉載,請註明出處,否則將追究法律責任。

相關文章