高水位(HWM)详解

来源:互联网 发布:动漫恶搞软件 编辑:程序博客网 时间:2024/06/02 20:05

什么是高水位线?

    所有的oracle段(segments,在此,为了理解方便,建议把segment作为表的一个同义词) 都有一个在段内容纳数据的上限,我们把这个上限称为"high water mark"或HWM。这个HWM是一个标记,用来说明已经有多少没有使用的数据块分配给这个segment。HWM通常增长的幅度为一次5个数据块,原则上HWM只会增大,不会缩小,即使将表中的数据全部删除,HWM还是为原值,由于这个特点,使HWM很象一个水库的历史最高水位,这也就是HWM的原始含义,当然不能说一个水库没水了,就说该水库的历史最高水位为0。但是如果我们在表上使用了truncate命令,则该表的HWM会被重新置为0。

    全表扫描通常要读出直到HWM标记的所有的属于该表数据库块,即使该表中没有任何数据。

    即使HWM以下有空闲的数据库块,键入在插入数据时使用了append关键字,则在插入时使用HWM以上的数据块,此时HWM会自动增大。

   

如何查看表的高水位?

    a) 首先对表进行分析:

ANALYZE TABLE <tablename> ESTIMATE/COMPUTE STATISTICS;

     ESTIMATE:是估算,一般推荐用这个速度快

     COMPUTE:全部计算,一般小表用这个


    b)查看表的高水位

    select table_name,num_rows,blocks,empty_blocks from user_tables where table_name='table_name'

    BLOCKS 列代表该表中曾经使用过得数据库块的数目,即水线。

    EMPTY_BLOCKS 代表分配给该表,但是在水线以上的数据库块,即从来没有使用的数据块。

实验:

       环境10g

       SQL> create table table_1 (col1 number(10), col2 varchar(100));
      表已创建。

       SQL> col segment_name,segment_type format a20;
       SQL> col blocks format 9999;

       SQL> select segment_name,segment_type,blocks from dba_segments where segment_name='TABLE_1';查看初始分配块
       SEGMENT_NAME         SEGMENT_TYPE         BLOCKS
        --------------------               --------------------              ------
       TABLE_1                        TABLE                             8

       SQL> select table_name,num_rows,blocks,empty_blocks from dba_tables where table_name='TABLE_1';
       TABLE_NAME     NUM_ROWS BLOCKS EMPTY_BLOCKS
       ------------              ----------            ------         ------------
       TABLE_1               0                     0               7

     

      插入数据:

     SQL> declare
  2  i number(10);
  3  begin
  4  for i in 1..100000 loop
  5  insert into table_1 values(i,'nihao');
  6  end loop;
  7  commit;
  8  end;
  9  /
  PL/SQL 过程已成功完成。

     SQL> select segment_name,segment_type,blocks from dba_segments where segment_name='TABLE_1';插入数据后总分配的块
     SEGMENT_NAME         SEGMENT_TYPE         BLOCKS
     --------------------               --------------------               ------
     TABLE_1                        TABLE                              256

   

     SQL> ANALYZE TABLE table_1 ESTIMATE STATISTICS;
     表已分析。

    

     SQL> select table_name,num_rows,blocks,empty_blocks from dba_tables where table_name='TABLE_1';查看高水位
     TABLE_NAME     NUM_ROWS BLOCKS EMPTY_BLOCKS
     ------------              ----------            ------         ------------
     TABLE_1             100000           222           33

     BLOCKS + EMPTY_BLOCKS (222+33=255)比DBA_SEGMENTS.BLOCKS少1个数据库块,这是因为有一个数据库块被保留用作segment header.DBA_SEGMENTS.BLOCKS 表示分配给这个表的所有的数据库块的数目。DBA_TABLES.BLOCKS表示已经使用过的数据库块的数目.


如何修正HWM?

    1: alter table table_name deallocate unused 会改变dba_segments.blocks总的块数,和dba_tables.empty_blocks数,就是回收空的块。

  SQL> alter table table_1 deallocate unused;
    表已更改。
    SQL> select segment_name,segment_type,blocks from dba_segments where segment_name='TABLE_1';
    SEGMENT_NAME         SEGMENT_TYPE         BLOCKS
    --------------------                --------------------             ------
    TABLE_1                          TABLE                            224
    SQL> select table_name,num_rows,blocks,empty_blocks from dba_tables where table_name='TABLE_1';
    TABLE_NAME     NUM_ROWS BLOCKS EMPTY_BLOCKS
    ------------              ----------            ------         ------------
    TABLE_1             100000           222           1

    2:truncate table table_name   会删除表中数据,并改变hwm.

    SQL> truncate table table_1;
    表被截断。

    SQL> ANALYZE TABLE table_1 ESTIMATE STATISTICS;
    表已分析。
    SQL> select segment_name,segment_type,blocks from dba_segments where segment_name='TABLE_1';
    SEGMENT_NAME         SEGMENT_TYPE         BLOCKS
    --------------------                --------------------             ------
    TABLE_1                          TABLE                              8
    SQL> select table_name,num_rows,blocks,empty_blocks from dba_tables where table_name='TABLE_1';
    TABLE_NAME     NUM_ROWS BLOCKS EMPTY_BLOCKS
     ------------              ----------           ------          ------------
    TABLE_1               0                       0              7

    3:alter table table_name move 移动到本表空间

          alter table table_name move tablespace tablespace_name 

         move之后需要重建索引, 如果以后还要继续向这个表增加数据,没有必要move,因为释放出来的空间,只能这个表用,其他的表或者segment无法使用该空间

    移动前:

    SQL> select table_name,num_rows,blocks,empty_blocks from dba_tables where table_name='TABLE_1';
    TABLE_NAME     NUM_ROWS BLOCKS EMPTY_BLOCKS
     ------------             ----------           ------          ------------
    TABLE_1             100000           305           78

    移动后:

    SQL> select table_name,num_rows,blocks,empty_blocks from dba_tables where table_name='TABLE_1';
    TABLE_NAME     NUM_ROWS BLOCKS EMPTY_BLOCKS
     ------------             ----------           ------          ------------
    TABLE_1             100000           303           80

    4:alter table table_name shrink space,但必须允许行移动 alter table table_name enable row movement;并且手动管理表空间里的表不能用

     SHRINK SPACE有两种option:   COMPACT & CASCADE, 前者是基于行的Shrink, 减少segment的碎片,使列变得更紧凑,但不会改变HWM, 不会对锁表,但对行会有时间很短的锁,如果这个时候有DML没提交,你的shrink操作就会处在等待状态,但shrink不会让你的DML操作等待很久; 后者会修改HWM, 会对segment产生锁,但时间比较短。做好不要放在忙时操作

    shrink space前:

    SQL> select table_name,num_rows,blocks,empty_blocks from dba_tables where table_name='TABLE_1';
    TABLE_NAME     NUM_ROWS BLOCKS EMPTY_BLOCKS
     ------------             ----------           ------          ------------
    TABLE_1             100000           306           78


    alter table table_1 shrink space;之后

        SQL> select table_name,num_rows,blocks,empty_blocks from dba_tables where table_name='TABLE_1';
    TABLE_NAME     NUM_ROWS BLOCKS EMPTY_BLOCKS
     ------------             ----------           ------          ------------
    TABLE_1             100000           305           15

  5.复制要保留的数据到临时表t,drop原表,然后rename临时表t为原表

  原表数据:

    SQL> select table_name,num_rows,blocks,empty_blocks from dba_tables where table_name='TABLE_1';
    TABLE_NAME     NUM_ROWS BLOCKS EMPTY_BLOCKS
     ------------             ----------           ------          ------------
    TABLE_1             100000           306           78

    create table t1 as select * from table_1
    drop table table_1
    alter table t1 rename to table_1 之后

    SQL> select table_name,num_rows,blocks,empty_blocks from dba_tables where table_name='TABLE_1';
    TABLE_NAME     NUM_ROWS BLOCKS EMPTY_BLOCKS
     ------------             ----------           ------          ------------
    TABLE_1             100000           303           80

    6:逻辑导入导出 exp/imp expdp/impdp