当前位置: 代码迷 >> 综合 >> 也说Oracle High Water Mark
  详细解决方案

也说Oracle High Water Mark

热度:77   发布时间:2023-12-08 19:01:02.0
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没有改变。

  相关解决方案