高水位线HWM到底在哪儿?

您当前位置: 首页» Internal Oracle » 高水位线HWM到底在哪儿?

高水位线HWM到底在哪儿?

2014年9月3日 | mac

高水位线是Oracle段对象的一个重要参数。对Oracle Segment对象而言,HWM(High Water Mark)标记着数据使用过的最高位置,有时也称为格式化过的数据位置。

当Oracle数据表进行FTS(全表扫描)操作的时候,会从段头一直检索到HWM位置。本篇中,我们一起从逻辑结构分析的角度,来研究一下HWM的确切位置。

1、环境准备

我们选择在Oracle 10g下进行试验,准备数据表T。

 

Source code    
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“表-段-区-块”的层次顺序,分析一下对应数据表的情况。

 

Source code    
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个分区中。

 

Source code    
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

 

Oracle对segment的空间分配,是按照一个extent一个extent进行的。当当前的extent使用完,并且没有可以使用的空间时,Oracle会给segment一个新的extent使用,分配新的extent_id编号。

HWM记录的位置是在数据段segment的段头块中。我们通过dba_segments视图,可以知道对应的段头块为fno=1,blockno=63057。我们使用dump命令,可以将其逻辑结构展现出来。

 

Source code    
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。

 

Source code    
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中,我们可以看到对应的21个extents使用分配情况。段头块中记录着HWM的位置地址,其中的(Highwater:: 0x0040fa42)就表示这个具体位置。

注意:当Oracle要进行FTS的时候,首先访问的就是段头segment header块。从其中,可以获得分配的分区信息(Map Header)和Scan截止位置HWM。

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

 

Source code    
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。

那么,我们检查一下这个位置在哪里。

 

Source code    
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编号下的一个数据块。我们可以看一下对应的相邻数据块中内容。

–高水位线对应数据块

 

Source code    
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的变化情况。

3、HWM变化

下面我们观察一下HWM在insert,delete和move操作时候的变化。

当进行insert操作时,如果是一个heap表的话,首先会在堆中寻找空位插入。如果没有找到,就推高HWM到一个新的块位置。

我们继续在上面实验的基础上,进行试验。

 

Source code    
SQL> insert into t select * from dba_objects where wner='SCOTT';
 
25 rows inserted
 
SQL> commit;
 
Commit complete

 

此时,我们dump出数据块查看HWM情况。

 

Source code    
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操作呢?

 

Source code    
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下降的两个常见命令,Move和Truncate效果如何呢?

 

Source code    
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

 

此时,头块位置已经发生改变!!

 

Source code    
SQL> alter system dump datafile 1 block 63441;
 
System altered

 

Move操作影响到了头块位置,HWM位置必然发生变化。

 

Source code    
-----------------------------------------------------------------
 
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命令。

 

Source code    
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出头块情况。

 

Source code    
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。

 

Source code    
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的作用十分重要,需要我们深刻理解。

原创文章,转载请注明: 转载自Hello,Oracle

本文链接地址: 高水位线HWM到底在哪儿?

文章的脚注信息由WordPress的wp-posturl插件自动生成

分类:

Internal Oracle

| 标签:

你可能感兴趣的:(高水位线HWM到底在哪儿?)