HWM是数据段中使用空间和未使用空间之间的界限,假如现有自由链表上的数据块不能满足需求,Oracle把HWM指向的数据块加入到自由链表上,HWM向前移动到下一个数据块。简单说,一个数据段中,HWM左边是使用的数据块,右边是目前还没有被使用的数据块。
一个表在表空间中创建以后,会先分配一些初始的数据区。随着表中行数的增加,区也会相应的扩展,DBA_SEGMENTS试图的BLOCKS和EXTENTS列记录了相应的数据区块的信息。
SQL> create table test(id number);
Table created.
SQL> select blocks, extents from dba_segments where segment_name='TEST' and owner='HR';
BLOCKS EXTENTS
---------- ----------
8 1
现在对表进行分析,以查看HWM。
SQL> analyze table test compute statistics;
Table analyzed.
SQL> select blocks, empty_blocks, num_rows from dba_tables where table_name='TEST' and owner='HR';
BLOCKS EMPTY_BLOCKS NUM_ROWS
---------- ------------ ----------
0 8 0
现在我们往表中插入一些数据,再来查看HWM。
SQL> insert into test select object_id from user_objects;
142 rows created.
SQL> commit;
Commit complete.
SQL> analyze table test compute statistics;
Table analyzed.
SQL> select blocks, empty_blocks, num_rows from dba_tables where table_name='TEST' and owner='HR';
BLOCKS EMPTY_BLOCKS NUM_ROWS
---------- ------------ ----------
5 3 142
可以看出此时的HWM应该在blocks=6的位置,虽然这里分配了5个数据块,但数据不一定占据了5个块的位置。
要想获取该表使用的确切的数据块,可以使用下面的查询。
SQL> select count(distinct dbms_rowid.rowid_block_number(rowid)||'-'||
dbms_rowid.rowid_relative_fno(rowid)) used_blocks
from test;
used blocks
-----------
1
从这里可以看出test表占用了8个数据块,有5个被格式化以准备接收数据,但实际存储数据的只有一个数据块。
我们把这几个块导出来查看一下。
SQL> select distinct dbms_rowid.rowid_relative_fno(rowid), dbms_rowid.rowid_block_number(rowid) from test;
DBMS_ROWID.ROWID_RELATIVE_FNO(ROWID) DBMS_ROWID.ROWID_BLOCK_NUMBER(ROWID)
------------------------------------ ------------------------------------
4 4348
SQL> alter system dump datafile 4 block min 4348 block max 4350;
System altered.
相应的trace文件中,可以发现下面的信息。
data_block_dump,data header at 0xeb19464
===============
tsiz: 0x1f98
hsiz: 0x12e
pbl: 0x0eb19464
bdba: 0x010010fc
76543210
flag=--------
ntab=1
nrow=142
......
data_block_dump,data header at 0xeb19464
===============
tsiz: 0x1f98
hsiz: 0xe
pbl: 0x0eb19464
bdba: 0x010010fe
76543210
flag=--------
ntab=0
nrow=0
可以看到,142行只存在于 bdba: 0x010010fc 这个块中,也就是datafile=4,block=4348的数据块。
说到HWM就不能不提如何的降低一个表的HWM,因为如果一个表插入了大量的数据然后又被删除其中的一部分,表的HWM是不会下降的。在全表扫描的时候仍然会扫描到HWM的位置,这样必然导致IO资源的浪费。
删除记录不会降低HWM,因此,删除记录不会导致EMPTY_BLOCKS块的增加,即使使用'alter table test deallocate unused;'命令也不行。改变表的HWM可以使用truncate table test;和alter table test move tablespace xxx;等方法。当然,10g中也可以使用alter table test shrink space;。
现在使用具体的实例来说明各种方法对HWM的影响。
首先采用移动表空间的方法。
SQL> create table t(a number, b number, c number, d number, e number, f number);
Table created.
SQL> create or replace procedure populate (numrows in number) is
fa number; fb number; fc number; fd number; fe number; ff number;
begin
dbms_random.Initialize(1234567);
for i in 1..numrows loop
fa:=mod(abs(dbms_random.random),10)+1991;
fb:=mod(abs(dbms_random.random),2);
fc:=mod(abs(dbms_random.random),20);
fd:=mod(abs(dbms_random.random),30);
fe:=mod(abs(dbms_random.random),40);
ff:=mod(abs(dbms_random.random),10);
insert into t values(fa,fb,fc,fd,fe,ff);
if mod(i,100)=0 then commit; end if;
end loop;
dbms_random.Terminate;
end;
/
Procedure created.
SQL> set serveroutput on
SQL> execute populate(200000);
PL/SQL procedure successfully completed.
SQL> delete from t where a=1991 and b=0;
9991 rows deleted.
SQL> commit;
Commit complete.
SQL> delete from t where f=9;
13911 rows deleted.
SQL> analyze table t compute statistics;
Table analyzed.
SQL> select num_rows,blocks,empty_blocks from dba_tables where table_name='T';
NUM_ROWS BLOCKS EMPTY_BLOCKS
---------- ---------- ------------
171270 684 84
SQL> alter table t move tablespace users;
Table altered.
SQL> select num_rows,blocks,empty_blocks from dba_tables where table_name='T';
NUM_ROWS BLOCKS EMPTY_BLOCKS
---------- ---------- ------------
171270 684 84
SQL> analyze table t compute statistics;
Table analyzed.
SQL> select num_rows,blocks,empty_blocks from dba_tables where table_name='T';
NUM_ROWS BLOCKS EMPTY_BLOCKS
---------- ---------- ------------
171270 569 71
可以看到,重新分析后,表的HWM下降了。说明移动表空间的方法是可以降低HWM的,即使移动前后的表空间是相同的。
接下来,再来看看export/import对HWM的影响。
首先导出T表中的所有数据,
$ exp hr/hr tables='t'
......
About to export specified tables via Conventional Path ...
. . exporting table T 171270 rows exported
SQL> delete from t;
171270 rows deleted.
SQL> commit;
Commit complete.
SQL> analyze table t compute statistics;
Table analyzed.
SQL> select num_rows, blocks, empty_blocks from dba_tables where table_name='T';
NUM_ROWS BLOCKS EMPTY_BLOCKS
---------- ---------- ------------
0 569 71 --虽然行数变了,但是HWM仍然没有改变
$ imp hr/hr ignore=y file=expdat.dmp full=y
......
. importing HR's objects into HR
. . importing table "T" 171270 rows imported
SQL> analyze table t compute statistics;
Table analyzed.
SQL> select num_rows, blocks, empty_blocks from dba_tables where table_name='T';
NUM_ROWS BLOCKS EMPTY_BLOCKS
---------- ---------- ------------
171270 569 71
可以看出import之后,表的HWM没有改变。
一个表在表空间中创建以后,会先分配一些初始的数据区。随着表中行数的增加,区也会相应的扩展,DBA_SEGMENTS试图的BLOCKS和EXTENTS列记录了相应的数据区块的信息。
SQL> create table test(id number);
Table created.
SQL> select blocks, extents from dba_segments where segment_name='TEST' and owner='HR';
BLOCKS EXTENTS
---------- ----------
8 1
现在对表进行分析,以查看HWM。
SQL> analyze table test compute statistics;
Table analyzed.
SQL> select blocks, empty_blocks, num_rows from dba_tables where table_name='TEST' and owner='HR';
BLOCKS EMPTY_BLOCKS NUM_ROWS
---------- ------------ ----------
0 8 0
现在我们往表中插入一些数据,再来查看HWM。
SQL> insert into test select object_id from user_objects;
142 rows created.
SQL> commit;
Commit complete.
SQL> analyze table test compute statistics;
Table analyzed.
SQL> select blocks, empty_blocks, num_rows from dba_tables where table_name='TEST' and owner='HR';
BLOCKS EMPTY_BLOCKS NUM_ROWS
---------- ------------ ----------
5 3 142
可以看出此时的HWM应该在blocks=6的位置,虽然这里分配了5个数据块,但数据不一定占据了5个块的位置。
要想获取该表使用的确切的数据块,可以使用下面的查询。
SQL> select count(distinct dbms_rowid.rowid_block_number(rowid)||'-'||
dbms_rowid.rowid_relative_fno(rowid)) used_blocks
from test;
used blocks
-----------
1
从这里可以看出test表占用了8个数据块,有5个被格式化以准备接收数据,但实际存储数据的只有一个数据块。
我们把这几个块导出来查看一下。
SQL> select distinct dbms_rowid.rowid_relative_fno(rowid), dbms_rowid.rowid_block_number(rowid) from test;
DBMS_ROWID.ROWID_RELATIVE_FNO(ROWID) DBMS_ROWID.ROWID_BLOCK_NUMBER(ROWID)
------------------------------------ ------------------------------------
4 4348
SQL> alter system dump datafile 4 block min 4348 block max 4350;
System altered.
相应的trace文件中,可以发现下面的信息。
data_block_dump,data header at 0xeb19464
===============
tsiz: 0x1f98
hsiz: 0x12e
pbl: 0x0eb19464
bdba: 0x010010fc
76543210
flag=--------
ntab=1
nrow=142
......
data_block_dump,data header at 0xeb19464
===============
tsiz: 0x1f98
hsiz: 0xe
pbl: 0x0eb19464
bdba: 0x010010fe
76543210
flag=--------
ntab=0
nrow=0
可以看到,142行只存在于 bdba: 0x010010fc 这个块中,也就是datafile=4,block=4348的数据块。
说到HWM就不能不提如何的降低一个表的HWM,因为如果一个表插入了大量的数据然后又被删除其中的一部分,表的HWM是不会下降的。在全表扫描的时候仍然会扫描到HWM的位置,这样必然导致IO资源的浪费。
删除记录不会降低HWM,因此,删除记录不会导致EMPTY_BLOCKS块的增加,即使使用'alter table test deallocate unused;'命令也不行。改变表的HWM可以使用truncate table test;和alter table test move tablespace xxx;等方法。当然,10g中也可以使用alter table test shrink space;。
现在使用具体的实例来说明各种方法对HWM的影响。
首先采用移动表空间的方法。
SQL> create table t(a number, b number, c number, d number, e number, f number);
Table created.
SQL> create or replace procedure populate (numrows in number) is
fa number; fb number; fc number; fd number; fe number; ff number;
begin
dbms_random.Initialize(1234567);
for i in 1..numrows loop
fa:=mod(abs(dbms_random.random),10)+1991;
fb:=mod(abs(dbms_random.random),2);
fc:=mod(abs(dbms_random.random),20);
fd:=mod(abs(dbms_random.random),30);
fe:=mod(abs(dbms_random.random),40);
ff:=mod(abs(dbms_random.random),10);
insert into t values(fa,fb,fc,fd,fe,ff);
if mod(i,100)=0 then commit; end if;
end loop;
dbms_random.Terminate;
end;
/
Procedure created.
SQL> set serveroutput on
SQL> execute populate(200000);
PL/SQL procedure successfully completed.
SQL> delete from t where a=1991 and b=0;
9991 rows deleted.
SQL> commit;
Commit complete.
SQL> delete from t where f=9;
13911 rows deleted.
SQL> analyze table t compute statistics;
Table analyzed.
SQL> select num_rows,blocks,empty_blocks from dba_tables where table_name='T';
NUM_ROWS BLOCKS EMPTY_BLOCKS
---------- ---------- ------------
171270 684 84
SQL> alter table t move tablespace users;
Table altered.
SQL> select num_rows,blocks,empty_blocks from dba_tables where table_name='T';
NUM_ROWS BLOCKS EMPTY_BLOCKS
---------- ---------- ------------
171270 684 84
SQL> analyze table t compute statistics;
Table analyzed.
SQL> select num_rows,blocks,empty_blocks from dba_tables where table_name='T';
NUM_ROWS BLOCKS EMPTY_BLOCKS
---------- ---------- ------------
171270 569 71
可以看到,重新分析后,表的HWM下降了。说明移动表空间的方法是可以降低HWM的,即使移动前后的表空间是相同的。
接下来,再来看看export/import对HWM的影响。
首先导出T表中的所有数据,
$ exp hr/hr tables='t'
......
About to export specified tables via Conventional Path ...
. . exporting table T 171270 rows exported
SQL> delete from t;
171270 rows deleted.
SQL> commit;
Commit complete.
SQL> analyze table t compute statistics;
Table analyzed.
SQL> select num_rows, blocks, empty_blocks from dba_tables where table_name='T';
NUM_ROWS BLOCKS EMPTY_BLOCKS
---------- ---------- ------------
0 569 71 --虽然行数变了,但是HWM仍然没有改变
$ imp hr/hr ignore=y file=expdat.dmp full=y
......
. importing HR's objects into HR
. . importing table "T" 171270 rows imported
SQL> analyze table t compute statistics;
Table analyzed.
SQL> select num_rows, blocks, empty_blocks from dba_tables where table_name='T';
NUM_ROWS BLOCKS EMPTY_BLOCKS
---------- ---------- ------------
171270 569 71
可以看出import之后,表的HWM没有改变。