對Oracle高水位線的研究實踐

kingsql發表於2014-08-22

高水位線是Oracle段物件的一個重要引數。對Oracle Segment物件而言,HWMHigh Water Mark)標記著資料使用過的最高位置,有時也稱為格式化過的資料位置。

 

Oracle資料表進行FTS(全表掃描)操作的時候,會從段頭一直檢索到HWM位置。本篇中,我們一起從邏輯結構分析的角度,來研究一下HWM的確切位置。

 

1、環境準備

 

我們選擇在Oracle 10g下進行試驗,準備資料表T

 

 

SQL> select * from v$version;

BANNER

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

Oracle Database 10g Enterprise Edition Release 10.2.0.1.0 - Prod

PL/SQL Release 10.2.0.1.0 - Production

CORE     10.2.0.1.0       Production

 

SQL> show user

User is "SYS"

 

SQL> create table t as select * from dba_objects;

Table created

 

SQL> exec dbms_stats.gather_table_stats(user,'T',cascade => true);

PL/SQL procedure successfully completed

 

 

2、原始HWM位置分析

 

根據Oracle“表---塊”的層次順序,分析一下對應資料表的情況。

 

 

SQL> select HEADER_FILE, HEADER_BLOCK, BYTES, BLOCKS, EXTENTS from dba_segments where wner='SYS' and segment_name='T';

 

HEADER_FILE HEADER_BLOCK      BYTES     BLOCKS    EXTENTS

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

          1        63057    6291456        768         21

 

 

 

對應768個資料塊,包括21個分割槽中。

 

 

SQL> select EXTENT_ID, FILE_ID, BLOCK_ID, BYTES, BLOCKS from dba_extents where wner='SYS' and segment_name='T';

 

 EXTENT_ID    FILE_ID   BLOCK_ID      BYTES     BLOCKS

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

         0          1      63057      65536          8

(篇幅原因,有省略……

        19          1      63881    1048576        128

        20          1      64009    1048576        128

 

21 rows selected

 

 

Oraclesegment的空間分配,是按照一個extent一個extent進行的。噹噹前的extent使用完,並且沒有可以使用的空間時,Oracle會給segment一個新的extent使用,分配新的extent_id編號。

 

HWM記錄的位置是在資料段segment的段頭塊中。我們透過dba_segments檢視,可以知道對應的段頭塊為fno=1blockno=63057。我們使用dump命令,可以將其邏輯結構展現出來。

 

 

SQL> select f_get_trace_name from dual;

 

F_GET_TRACE_NAME

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

D:\ADMIN\ORCL\UDUMP\orcl_ora_1984.trc

 

SQL> alter system dump datafile 1 block 63057;

System altered

 

 

trace檔案中,我們找到HWM位置記錄和對應的Extent分配map

 

 

Extent Header:: spare1: 0      spare2: 0      #extents: 21     #blocks: 767  

                  last map  0x00000000  #maps: 0      offset: 4128 

      Highwater::  0x0040fa42  ext#: 20     blk#: 57     ext size: 128  

  #blocks in seg. hdr's freelists: 0    

  #blocks below: 696  

  mapblk  0x00000000  offset: 20   

                   Unlocked

     Map Header:: next  0x00000000  #extents: 21   obj#: 56436  flag: 0x40000000

  Extent Map

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

   0x0040f652  length: 7    

   0x0040f659  length: 8    

   (篇幅原因,省略…..

   0x0040f909  length: 128  

   0x0040f989  length: 128  

   0x0040fa09  length: 128 

 

 

extent allocation map中,我們可以看到對應的21extents使用分配情況。段頭塊中記錄著HWM的位置地址,其中的(Highwater::  0x0040fa42)就表示這個具體位置。

 

注意:當Oracle要進行FTS的時候,首先訪問的就是段頭segment header塊。從其中,可以獲得分配的分割槽資訊(Map Header)和Scan截止位置HWM

 

下面考慮解析HWM地址。在Oracle 10g中,我們可以使用dbms_utility包方法進行解析。

 

 

SQL> select to_number('40fa42','xxxxxx') from dual;

 

TO_NUMBER('40FA42','XXXXXX')

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

                     4258370

 

SQL> select dbms_utility.data_block_address_file(4258370) from dual;

 

DBMS_UTILITY.DATA_BLOCK_ADDRES

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

                             1

 

SQL> select dbms_utility.data_block_address_block(4258370) from dual;

 

DBMS_UTILITY.DATA_BLOCK_ADDRES

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

                         64066

 

 

可以知道,對應HWM指向的位置是在檔案編號為1的檔案中,對應塊號為64066

 

那麼,我們檢查一下這個位置在哪裡。

 

 

SQL> select EXTENT_ID, FILE_ID, BLOCK_ID, BYTES, BLOCKS from dba_extents where wner='SYS' and segment_name='T' and (block_id<=64066 and block_id+blocks-1>=64066) and file_id=1;

 

 EXTENT_ID    FILE_ID   BLOCK_ID      BYTES     BLOCKS

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

        20          1      64009    1048576        128

 

 

對應的blockno=64066為最大extent編號下的一個資料塊。我們可以看一下對應的相鄰資料塊中內容。

 

--高水位線對應資料塊

SQL>  select count(*) from t where dbms_rowid.rowid_relative_fno(t.rowid)=1 and dbms_rowid.rowid_block_number(t.rowid)=64066;

  COUNT(*)

----------

         0

 

-高水位線對應上一個資料塊

SQL>  select count(*) from t where dbms_rowid.rowid_relative_fno(t.rowid)=1 and dbms_rowid.rowid_block_number(t.rowid)=64065;

  COUNT(*)

----------

         1

 

---高水位線對應上上個資料塊

SQL>  select count(*) from t where dbms_rowid.rowid_relative_fno(t.rowid)=1 and dbms_rowid.rowid_block_number(t.rowid)=64064;

  COUNT(*)

----------

        65

 

---高水位線對應下一個資料塊

SQL>  select count(*) from t where dbms_rowid.rowid_relative_fno(t.rowid)=1 and dbms_rowid.rowid_block_number(t.rowid)=64067;

  COUNT(*)

----------

         0

 

 

從上面的資料,我們可以清晰的看到HWM的對應。HWM位於segment編號最大的extent中的一個資料塊。在Oracle中,HWM對應的資料塊是那個沒有使用過的資料塊。HWM上面的就是正在使用的最大資料塊。

 

那麼,我們觀察一下,在新增和刪除過程中,HWM的變化情況。

 

3HWM變化

 

下面我們觀察一下HWMinsertdeletemove操作時候的變化。

 

當進行insert操作時,如果是一個heap表的話,首先會在堆中尋找空位插入。如果沒有找到,就推高HWM到一個新的塊位置。

 

我們繼續在上面實驗的基礎上,進行試驗。

 

 

SQL> insert into t select * from dba_objects where wner='SCOTT';

25 rows inserted

 

SQL> commit;

Commit complete

 

 

此時,我們dump出資料塊檢視HWM情況。

 

 

Extent Header:: spare1: 0      spare2: 0      #extents: 21     #blocks: 767  

                  last map  0x00000000  #maps: 0      offset: 4128 

      Highwater::  0x0040fa47  ext#: 20     blk#: 62     ext size: 128   

  #blocks in seg. hdr's freelists: 5    

  #blocks below: 701  

 

 

水位線位置從原來的0x0040fa42變化到0x0040fa47。真實對應的位置如下:

 

 

SQL> select to_number('40fa47','xxxxxx') from dual;

 

TO_NUMBER('40FA47','XXXXXX')

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

                     4258375

 

SQL> select dbms_utility.data_block_address_file(4258375) from dual;

 

DBMS_UTILITY.DATA_BLOCK_ADDRES

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

                             1

 

SQL> select dbms_utility.data_block_address_block(4258375) from dual;

 

DBMS_UTILITY.DATA_BLOCK_ADDRES

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

                         64071

 

 

對應從原來的64066塊偏移到了64071塊,移動了5個資料塊。結論:確實insert操作可能會推高水位線位置。

 

那麼,一般的delete操作呢?

 

 

SQL> delete t where wner='SCOTT';

50 rows deleted

 

SQL> commit;

Commit complete

 

SQL> alter system dump datafile 1 block 63057;

System altered

 

 

此時,HWM位置為:

 

 

Extent Control Header

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

  Extent Header:: spare1: 0      spare2: 0      #extents: 21     #blocks: 767  

                  last map  0x00000000  #maps: 0      offset: 4128 

      Highwater::  0x0040fa47  ext#: 20     blk#: 62     ext size: 128  

  #blocks in seg. hdr's freelists: 6    

  #blocks below: 701  

  mapblk  0x00000000  offset: 20   

                   Unlocked

     Map Header:: next  0x00000000  #extents: 21   obj#: 56436  flag: 0x40000000

 

 

資料HWM位置沒有發生變化,說明HWM確實不會在delete的時候下降。

 

影響HWM下降的兩個常見命令,MoveTruncate效果如何呢?

 

 

SQL> alter table t move;

Table altered

 

SQL> select HEADER_FILE, HEADER_BLOCK, BYTES, BLOCKS, EXTENTS from dba_segments where wner='SYS' and segment_name='T';

 

HEADER_FILE HEADER_BLOCK      BYTES     BLOCKS    EXTENTS

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

          1        63441    6291456        768         21

 

 

此時,頭塊位置已經發生改變!!

 

 

SQL> alter system dump datafile 1 block 63441;

System altered

 

 

Move操作影響到了頭塊位置,HWM位置必然發生變化。

 

 

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

  Extent Header:: spare1: 0      spare2: 0      #extents: 21     #blocks: 767  

                  last map  0x00000000  #maps: 0      offset: 4128 

      Highwater::  0x0040fd41  ext#: 20     blk#: 56     ext size: 128  

  #blocks in seg. hdr's freelists: 0    

  #blocks below: 695  

  mapblk  0x00000000  offset: 20   

      Disk Lock:: Locked by xid:  0x0006.007.000005a6

     Map Header:: next  0x00000000  #extents: 21   obj#: 56512  flag: 0x40000000

 

 

最後,我們一起看一下truncate table命令。

 

 

SQL> truncate table t;

Table truncated

 

SQL> select HEADER_FILE, HEADER_BLOCK, BYTES, BLOCKS, EXTENTS from dba_segments where wner='SYS' and segment_name='T';

 

HEADER_FILE HEADER_BLOCK      BYTES     BLOCKS    EXTENTS

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

          1        63441      65536          8          1

 

 

注意:truncated table命令是不會影響到段頭塊的。

 

我們dump出頭塊情況。

 

 

SQL> alter system dump datafile 1 block 63441;

System altered

 

 

Dump出的資料塊結構如下:

 

 

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

  Extent Header:: spare1: 0      spare2: 0      #extents: 1      #blocks: 7    

                  last map  0x00000000  #maps: 0      offset: 4128 

      Highwater::  0x0040f7d2  ext#: 0      blk#: 0      ext size: 7    

  #blocks in seg. hdr's freelists: 0    

  #blocks below: 0    

  mapblk  0x00000000  offset: 0    

      Disk Lock:: Locked by xid:  0x0008.001.0000058b

     Map Header:: next  0x00000000  #extents: 1    obj#: 56513  flag: 0x40000000

  Extent Map

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

   0x0040f7d2  length: 7    

 

  nfl = 1, nfb = 1 typ = 1 nxf = 0 ccnt = 0

  SEG LST:: flg: UNUSED lhd: 0x00000000 ltl: 0x00000000

 

 

水位線下降到什麼位置呢?我們計算一下這個:0x0040f7d2

 

 

SQL> select to_number('40f7d2','xxxxxx') from dual;

 

TO_NUMBER('40F7D2','XXXXXX')

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

                     4257746

 

SQL> select dbms_utility.data_block_address_block(4257746) from dual;

 

DBMS_UTILITY.DATA_BLOCK_ADDRES

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

                         63442

 

SQL> select dbms_utility.data_block_address_file(4257746) from dual;

 

DBMS_UTILITY.DATA_BLOCK_ADDRES

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

                             1

 

 

注意:這裡的HWM指向塊號為63442。我們的資料段頭塊為63441。說明:在truncate table的時候,HWM要重置到頭塊後面的第一個資料塊上。

 

4、結論

 

經過上面的討論,我們已經可以清晰的看到Oracle HWM的位置和工作原則。對segment物件而言,HWM的作用十分重要,需要我們深刻理解。

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

相關文章