当前位置: 代码迷 >> 综合 >> 浅析ORACLE数据库高水位线(high water mark)
  详细解决方案

浅析ORACLE数据库高水位线(high water mark)

热度:75   发布时间:2023-12-15 07:46:23.0

ORACLE数据库逻辑结构包括:数据库块(block),扩展(extent 区),段(segment),表空间(tablespace)。高水位线就存在于段(segment)中,它用于标识段中已使用过的数据块与未使用地的数据块二者间交界,扫描表数据的时候,高水位线以下的所有数据块都必须被扫描。

 

首先需要提醒大家,高水位线存在于段,且高水位线的位置记录在段头,也就是段的第一个数据块中。因此,我们可以转存储段头信息来看高水位信息。

 

段又有很多种,数据段,索引段,临时段,回滚段等。当创建段的时候会分配区,区是由若干个物理连续的数据块组成。区的分配是需要初始化数据块的,默认初始化(format)单位为1M。记住,高水位线并不是初始化的交界片,被初始化过的数据库并不一定使用过。

 

以下通过实验来进一步阐述高水位线:

 

创建测试表

SQL> create table hwm as select * from dba_segments;

Table created.

SQL> BEGIN
  DBMS_STATS.gather_table_stats('SYS','HWM');
END;
  2    3    4 
  5  /

PL/SQL procedure successfully completed.

SQL> select HEADER_FILE,HEADER_BLOCK from DBA_SEGMENTS where SEGMENT_NAME='HWM'
;

HEADER_FILE HEADER_BLOCK
----------- ------------
   1    89168

SQL> ALTER SYSTEM DUMP DATAFILE 1 BLOCK 89168;

 

  Extent Header:: spare1: 0      spare2: 0      #extents: 13     #blocks: 103
                  last map  0x00000000  #maps: 0      offset: 4128
      Highwater::  0x00415cb5  ext#: 12     blk#: 5      ext size: 8
  #blocks in seg. hdr's freelists: 0
  #blocks below: 100
  mapblk  0x00000000  offset: 12  

 

删除3000行数据提交修改,再看看高水位线有没有变化:

SQL> delete from hwm where rownum < 3000;

2999 rows deleted.

SQL> commit;

Commit complete.

SQL> alter system checkpoint;

System altered.

SQL> ALTER SYSTEM DUMP DATAFILE 1 BLOCK 89168;

  Extent Control Header
  -----------------------------------------------------------------
  Extent Header:: spare1: 0      spare2: 0      #extents: 13     #blocks: 103  
                  last map  0x00000000  #maps: 0      offset: 4128 
      Highwater::  0x00415cb5  ext#: 12     blk#: 5      ext size: 8    
  #blocks in seg. hdr's freelists: 0    
  #blocks below: 100  
  mapblk  0x00000000  offset: 12   

 

并没有发现高水位线有变化,那么插入2000行继续观察

SQL> insert into hwm select * from dba_segments where rownum < 2001;

2000 rows created.

SQL> commit;

Commit complete.

SQL> alter system checkpoint;

System altered.

SQL> ALTER SYSTEM DUMP DATAFILE 1 BLOCK 89168;

System altered.
 
  Extent Control Header
  -----------------------------------------------------------------
  Extent Header:: spare1: 0      spare2: 0      #extents: 13     #blocks: 103  
                  last map  0x00000000  #maps: 0      offset: 4128 
      Highwater::  0x00415cb5  ext#: 12     blk#: 5      ext size: 8    
  #blocks in seg. hdr's freelists: 0    
  #blocks below: 100  
  mapblk  0x00000000  offset: 12   
                   Unlocked
     Map Header:: next  0x00000000  #extents: 13   obj#: 84253  flag: 0x40000000

高水位线并没有发生变化,说明高水位线以下的delete过的数据块是可以被复用的.

 

此时如果再插入1000行,高水位线应该是会变化的,求证一下:

SQL> insert into hwm select * from dba_segments where rownum < 1001;

1000 rows created.

SQL> commit;

Commit complete.

SQL> alter system checkpoint;

System altered.

SQL> ALTER SYSTEM DUMP DATAFILE 1 BLOCK 89168;

System altered.

  Extent Header:: spare1: 0      spare2: 0      #extents: 13     #blocks: 103  
                  last map  0x00000000  #maps: 0      offset: 4128 
      Highwater::  0x00415cb5  ext#: 12     blk#: 5      ext size: 8    
  #blocks in seg. hdr's freelists: 3    
  #blocks below: 100  
  mapblk  0x00000000  offset: 12   
                   Unlocked
     Map Header:: next  0x00000000  #extents: 13   obj#: 84254  flag: 0x40000000

    
发现高水位线依旧没有改变,继续插入新数据并观察:

SQL> insert into hwm select * from dba_segments where rownum < 1001;

1000 rows created.

SQL> commit;

Commit complete.

SQL> alter system checkpoint;

System altered.

SQL> ALTER SYSTEM DUMP DATAFILE 1 BLOCK 89168;

System altered.

 

  Extent Header:: spare1: 0      spare2: 0      #extents: 15     #blocks: 119  
                  last map  0x00000000  #maps: 0      offset: 4128 
      Highwater::  0x00415cc5  ext#: 14     blk#: 5      ext size: 8    
  #blocks in seg. hdr's freelists: 1    
  #blocks below: 116  
  mapblk  0x00000000  offset: 14   
                   Unlocked
     Map Header:: next  0x00000000  #extents: 15   obj#: 84254  flag: 0x40000000

 

以上可以看到,delete并不能回收表数据,在增删改表数据库的过程使得高水位线持续增长,且被删除的数据记录位置也无法100%复用,因此难免会存在碎片。比如,一张表100万数据,将全表数据delete之后,高水位线位置依旧在第100万行处,尽管此时表数据为0行,但全表扫描时候仍然需要扫描所有已使用过的数据块,全表扫描的效率将越来越低下。

因此oracle也提供了多种回收高水位线的方法,诸如:

  表重建, 如CATS(create table as select ...)

  导出导入(exp/imp,expdp/impdp)

  truncate(危险,因此慎用)

  shrink space

  move table

  DBMS_REDEFINITION表在线重定义

  等等

 

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

本文来自于我的技术博客 http://blog.csdn.net/robo23

转载请标注源文链接,否则追究法律责任!

 

  相关解决方案