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
转载请标注源文链接,否则追究法律责任!