Oracle降低高水位线的方法

Oracle  降低高水位线的方法 



高水位(HIGH WARTER MARK,HWM)好比水库中储水的水位,用于描述数据库中段的扩展方式。高水位对全表扫描方式有着至关重要的影响。当使用DELETE删除表记录时,高水位并不会下降,随之导致的是全表扫描的实际开销并没有任何减少。

创新互联建站是一家集网站建设,西盟企业网站建设,西盟品牌网站建设,网站定制,西盟网站建设报价,网络营销,网络优化,西盟网站推广为一体的创新建站企业,帮助传统企业提升企业形象加强企业竞争力。可充分满足这一群体相比中小企业更为丰富、高端、多元的互联网需求。同时我们时刻保持专业、时尚、前沿,时刻以成就客户成长自我,坚持不断学习、思考、沉淀、净化自己,让我们为更多的企业打造出实用型网站。

例如,首先新建一张空表,大小占用64K,然后插入数据直到表大小变为50G,此时使用DELETE删除所有的数据并且提交,这个时候查询表的大小的时候依然是50G,这就是因为表的高水位没有释放的缘故,而在这时如果使用“SELECT * FROM TABLE_NAME;”语句来查询数据的话,那么查询过程就会很慢,因为Oracle要执行全表扫描,从高水位下所有的块都得去扫描,直到50G的所有块全部扫描完毕。曾遇到一个同事使用DELETE删除了一个很大的分区表,然后执行SELECT查询很久都没有结果,以为是数据库HANG住了,其实这个问题是由于高水位的缘故。所以,表执行了TRUNCATE操作,再次SELECT的时候就可以很快返回结果了。

释放表的高水位通常有如下几种办法:

(1)对表进行MOVE操作:ALTER TABLE TABLE_NAME MOVE;。若表上存在索引,则记得重建索引。

(2)对表进行SHRINK SPACE操作:ALTER TABLE TABLE_NAME SHRINK SPACE;,注意,在执行该指令之前必须开启行移动:ALTER TABLE TABLE_NAME ENABLE ROW MOVEMENT;。该方法的优点是:在碎片整理结束后,表上相关的索引仍然有效,缺点是会产生大量的UNDO和REDO。

(3)复制要保留的数据到临时表T,DROP原表,然后RENAME临时表T为原表。

(4)exp/imp或expdp/impdp重构表。

(5)若表中没有数据则直接使用TRUNCATE来释放高水位。


如何找出系统中哪些表拥有高水位呢?这里给出两种办法,①比较表的行数和表的大小关系。如果行数为0,而表的当前占用大小减去初始化时的大小(INITIAL_EXTENT)后依然很大,那么说明该表有高水位。②行数和块数的比率,即查看一个块可以存储多少行数据。如果一个块存储的行数少于5行甚至更少,那么说明有高水位。注意,这两种方法都不是十分准确,需要再对查询结果进行筛选。需要注意的是,在查询表的高水位时,首先需要分析表,以得到最准确的统计信息。

下面给出用于查询高水位的几个SQL语句:

Segment Space and the High Water Mark

To manage space, Oracle Database tracks the state of blocks in the segment. The high water mark (HWM) is the point in a segment beyond which data blocks are unformatted and have never been used.

MSSM uses free lists to manage segment space. At table creation, no blocks in the segment are formatted. When a session first inserts rows into the table, the database searches the free list for usable blocks. If the database finds no usable blocks, then it preformats a group of blocks, places them on the free list, and begins inserting data into the blocks. In MSSM, a full table scan reads allblocks below the HWM.

ASSM does not use free lists and so must manage space differently. When a session first inserts data into a table, the database formats a single bitmap block instead of preformatting a group of blocks as in MSSM. The bitmap tracks the state of blocks in the segment, taking the place of the free list. The database uses the bitmap to find free blocks and then formats each block before filling it with data. ASSM spread out inserts among blocks to avoid concurrency issues.

Every data block in an ASSM segment is in one of the following states:

  • Above the HWM

    These blocks are unformatted and have never been used.

  • Below the HWM

    These blocks are in one of the following states:

    • Allocated, but currently unformatted and unused

    • Formatted and contain data

    • Formatted and empty because the data was deleted

Figure 12-23 depicts an ASSM segment as a horizontal series of blocks. At table creation, the HWM is at the beginning of the segment on the left. Because no data has been inserted yet, all blocks in the segment are unformatted and never used.

Figure 12-23 HWM at Table Creation

Oracle  降低高水位线的方法
Description of "Figure 12-23 HWM at Table Creation"

段空间和高水位标记

oracle数据库通过跟踪段中的块状态来管理空间。高水位标记(HWM)是段中的一个点,超过该点的数据块是未格式化和未使用过的。

MSSM使用空闲列表来管理段空间。在创建表时,段中的块并未被格式化。当一个会话初次向表中插入行时,数据库将搜索空闲列表来查找可用的块。如果数据库未找到可用的块,那么它会预格式化一组块,并将它们放置在空闲列表中,并开始将数据插入到块中。在MSSM中,全表扫描会读取HWM之下的所有块。

ASSM不使用空闲列表,所以必须以不同的方式管理空间。当会话初次向表中插入数据时,数据库只格式化一个单一位图块,而不像在MSSM中那样预格式化一组块。位图取代了空闲列表,用于跟踪在段中的块的状态。数据库使用位图来查找可用的块,然后在往块写入数据之前将其格式化。ASSM将插入操作分散到多个块,以避免并发问题。

在一个ASSM段中的每个数据块处于以下状态之一:

l 在HWM之上

    这些块是未格式化的,且从未使用过。

l 在HWM之下

这些块处于以下状态之一:

u 已分配,但当前未格式化且未使用

u 已格式化且包含数据

u 已格式化且为空,因为数据已被删除

图12-23将一个ASSM段描述为一系列水平的块。在创建表时,HWM在左侧段的开头。因为还未插入数据,段中的所有块都还是未格式化且从未使用过。

图将12-23在创建表时的HWM




Suppose that a transaction inserts rows into the segment. The database must allocate a group of blocks to hold the rows. The allocated blocks fall below the HWM. The database formats a bitmap block in this group to hold the metadata, but does not preformat the remaining blocks in the group.

In Figure 12-24, the blocks below the HWM are allocated, whereas blocks above the HWM are neither allocated or formatted. As inserts occur, the database can write to any block with available space. The low high water mark (low HWM) marks the point below which all blocks are known to be formatted because they either contain data or formerly contained data.

Figure 12-24 HWM and Low HWM

Oracle  降低高水位线的方法
Description of "Figure 12-24 HWM and Low HWM"

In Figure 12-25, the database chooses a block between the HWM and low HWM and writes to it. The database could have just as easily chosen any other block between the HWM and low HWM, or any block below the low HWM that had available space. In Figure 12-25, the blocks to either side of the newly filled block are unformatted.

Figure 12-25 HWM and Low HWM

Oracle  降低高水位线的方法
Description of "Figure 12-25 HWM and Low HWM"

The low HWM is important in a full table scan. Because blocks below the HWM are formatted only when used, some blocks could be unformatted, as in Figure 12-25. For this reason, the database reads the bitmap block to obtain the location of the low HWM. The database reads all blocks up to the low HWM because they are known to be formatted, and then carefully reads only the formatted blocks between the low HWM and the HWM.

Assume that a new transaction inserts rows into the table, but the bitmap indicates that insufficient free space exists under the HWM. In Figure 12-26, the database advances the HWM to the right, allocating a new group of unformatted blocks.

Figure 12-26 Advancing HWM and Low HWM

Oracle  降低高水位线的方法
Description of "Figure 12-26 Advancing HWM and Low HWM"

When the blocks between the HWM and low HWM are full, the HWM advances to the right and the low HWM advances to the location of the old HWM. As the database inserts data over time, the HWM continues to advance to the right, with the low HWM always trailing behind it. Unless you manually rebuild, truncate, or shrink the object, the HWM never retreats.

See Also:

  • Oracle Database Administrator's Guide to learn how to shrink segments online

  • Oracle Database SQL Language Reference for TRUNCATE TABLE syntax and semantics

move不但可以重置水位线(HWM),解决松散表带来的 IO 浪费,还可以解决表中的行迁移问题。
    move表的话需要双倍的空间,否则无法成功。move表可以通过重新安排数据文件的空间达到收缩数据文件的目的。
    move表时,会产生exclusive lock 锁,此时只能对表进行 select 操作。
    move表之后,如果表上有索引,记得重建。
2)shrink表只对ASSM管理的表有效,相关命令有:
    -----alter table TABLE_NAME shrink space;    整理碎片并回收空间
    -----alter table TABLE_NAME shrink space compact;     只整理碎片,不回收空间
     -----alter table TABLE_NAME shrink space cascate;      整理碎片回收空间,并连同表的级联对象一起整理(比如索引)
   能在线进行,不影响表上的DML操作,当然,并发的DML操作在shrink结束的时刻会出现短暂的block;
   shrink的另外一个优点是在碎片整理结束后,表上相关的index仍然enable。
3)move的操作速度远远快于shrink 操作 ,不是一般的快,不是一个数量级的,而且shrink 会产生大量的undo 和redo 操作。
4)truncate是DDL操作,相当于删表后重建。
5)还有其他的方法,如导出后再重新导入。

准备工作,创建一张表:
CREATE TABLE TEST2
(
    ID    NUMBER(10),
    NAME  VARCHAR2(32)
);

1、移动表:
SQL> begin
  2  for i in 1..10000 loop
  3  insert into test2 values(i,'bbb');
  4  end loop;
  5  commit;
  6  end;
  7  /
PL/SQL procedure successfully completed.

SQL>  select TABLE_NAME,TABLESPACE_NAME,BLOCKS,EMPTY_BLOCKS from user_tables where table_name='TEST2';
TABLE_NAME                     TABLESPACE_NAME                    BLOCKS EMPTY_BLOCKS
------------------------------ ------------------------------ ---------- ------------
TEST2                          LXM                                   244           12

SQL> delete test2;
100000 rows deleted.

SQL> alter table test2 move;
Table altered.

SQL> analyze table test2 compute statistics;
Table analyzed.

SQL> select TABLE_NAME,TABLESPACE_NAME,BLOCKS,EMPTY_BLOCKS from user_tables where table_name='TEST2';


TABLE_NAME                     TABLESPACE_NAME                    BLOCKS EMPTY_BLOCKS
------------------------------ ------------------------------ ---------- ------------
TEST2                          LXM                                     0            8

2、收缩表:
SQL>    begin
  2  for i in 1..100000 loop
  3  insert into test2 values(i,'kkk');
  4  end loop;
  5  commit;
  6  end;
  7  /
PL/SQL procedure successfully completed.

SQL> analyze table test2 compute statistics;
Table analyzed.

SQL> select TABLE_NAME,TABLESPACE_NAME,BLOCKS,EMPTY_BLOCKS from user_tables where table_name='TEST2';
TABLE_NAME                     TABLESPACE_NAME                    BLOCKS EMPTY_BLOCKS
------------------------------ ------------------------------ ---------- ------------
TEST2                          LXM                                   244           12

SQL> delete test2;
100000 rows deleted.

SQL> alter table test2 shrink space;
alter table test2 shrink space
*
ERROR at line 1:
ORA-10636: ROW MOVEMENT is not enabled

SQL> alter table test2 enable row movement;
Table altered.

SQL> alter table test2 shrink space;
Table altered.

SQL> analyze table test2 compute statistics;
Table analyzed.

SQL> select TABLE_NAME,TABLESPACE_NAME,BLOCKS,EMPTY_BLOCKS from user_tables where table_name='TEST2';
TABLE_NAME                     TABLESPACE_NAME                    BLOCKS EMPTY_BLOCKS
------------------------------ ------------------------------ ---------- ------------
TEST2                          LXM                                     1            7

3、truncate表
SQL> begin
  2  for i in 1..100000 loop
  3  insert into test2 values(i,'kkk');
  4  end loop;
  5  commit;
  6  end;
  7  /
PL/SQL procedure successfully completed.

SQL> analyze table test2 compute statistics;
Table analyzed.

SQL> select TABLE_NAME,TABLESPACE_NAME,BLOCKS,EMPTY_BLOCKS from user_tables where table_name='TEST2';
TABLE_NAME                     TABLESPACE_NAME                    BLOCKS EMPTY_BLOCKS
------------------------------ ------------------------------ ---------- ------------
TEST2                          LXM                                   244           12

SQL> truncate table test2;
Table truncated.

SQL> analyze table test2 compute statistics;
Table analyzed.

SQL> select TABLE_NAME,TABLESPACE_NAME,BLOCKS,EMPTY_BLOCKS from user_tables where table_name='TEST2';
TABLE_NAME                     TABLESPACE_NAME                    BLOCKS EMPTY_BLOCKS
------------------------------ ------------------------------ ---------- ------------
TEST2                          LXM                                     0            8


4、新建临时表,然后rename
SQL> begin
  2  for i in 1..100000 loop
  3  insert into test2 values(i,'kkk');
  4  end loop;
  5  commit;
  6  end;
  7  /
PL/SQL procedure successfully completed.

SQL> delete test2;
100000 rows deleted.

SQL> analyze table test2 compute statistics;
Table analyzed.

SQL> select TABLE_NAME,TABLESPACE_NAME,BLOCKS,EMPTY_BLOCKS from user_tables where table_name='TEST2';
TABLE_NAME                     TABLESPACE_NAME                    BLOCKS EMPTY_BLOCKS
------------------------------ ------------------------------ ---------- ------------
TEST2                          LXM                                   244           12

SQL> create table test3 as select * from test2;
Table created.

SQL> drop table test2;
Table dropped.

SQL> alter table test3 rename to test2;
Table altered.

SQL> analyze table test2 compute statistics;
Table analyzed.

SQL> select TABLE_NAME,TABLESPACE_NAME,BLOCKS,EMPTY_BLOCKS from user_tables where table_name='TEST2';
TABLE_NAME                     TABLESPACE_NAME                    BLOCKS EMPTY_BLOCKS
------------------------------ ------------------------------ ---------- ------------
TEST2                          LXM                                     0            0




==================================================
空表移动无须重建索引:
SQL> begin
  2  for i in 1..10000 loop
  3  insert into test2 values(i,'bbb');
  4  end loop;
  5  commit;
  6  end;
  7  /
PL/SQL procedure successfully completed.

SQL> select index_name,index_type,table_name,status,initial_extent,max_extents from user_indexes; 
INDEX_NAME                     INDEX_TYPE                  TABLE_NAME                     STATUS   INITIAL_EXTENT MAX_EXTENTS
------------------------------ --------------------------- ------------------------------ -------- -------------- -----------
IND_TEST2                      NORMAL                      TEST2                          VALID             65536  2147483645

SQL> delete test2 where id=1;
1 row deleted.
SQL> alter table test2 move;
Table altered.

SQL> select index_name,index_type,table_name,status,initial_extent,max_extents from user_indexes;
INDEX_NAME                     INDEX_TYPE                  TABLE_NAME                     STATUS   INITIAL_EXTENT MAX_EXTENTS
------------------------------ --------------------------- ------------------------------ -------- -------------- -----------
IND_TEST2                      NORMAL                      TEST2                          UNUSABLE          65536  2147483645

SQL> alter index ind_test2 rebuild;
Index altered.

SQL> select index_name,index_type,table_name,status,initial_extent,max_extents from user_indexes;
INDEX_NAME                     INDEX_TYPE                  TABLE_NAME                     STATUS   INITIAL_EXTENT MAX_EXTENTS
------------------------------ --------------------------- ------------------------------ -------- -------------- -----------
IND_TEST2                      NORMAL                      TEST2                          VALID             65536  2147483645

SQL> delete test2;
9999 rows deleted.
SQL> alter table test2 move;
Table altered.

SQL> select index_name,index_type,table_name,status,initial_extent,max_extents from user_indexes;
INDEX_NAME                     INDEX_TYPE                  TABLE_NAME                     STATUS   INITIAL_EXTENT MAX_EXTENTS
------------------------------ --------------------------- ------------------------------ -------- -------------- -----------
IND_TEST2                      NORMAL                      TEST2                          VALID             65536  2147483645



       水位是记录段里能容纳数据的上限,高水位存在段里

       全表扫先读段头块,而后在段头块里面找到HWM

        下面用实验由内而外来理解Oracle的HWM


[sql] view plain copy
 print?
  1. --t表有一条数据  
  2.   
  3. hr@ORCL> select * from t;  
  4.   
  5.         ID NAME  
  6. ---------- ----------  
  7.          1 AAAAA  
  8.   
  9. --找t段的段头块  
  10.   
  11. hr@ORCL> select header_file,header_block from dba_segments where segment_name='T' and owner='HR';  
  12.   
  13. HEADER_FILE HEADER_BLOCK  
  14. ----------- ------------  
  15.           4          387  
  16.   
  17. --另开一个session,dump段头块  
  18.   
  19. sys@ORCL> alter session set tracefile_identifier='sys_dump_t_01';  
  20.   
  21. Session altered.  
  22.   
  23. sys@ORCL> alter system dump datafile 4 block 387;  
  24.   
  25. System altered.  

       dump的部分trc内容摘入



[sql] view plain copy
 print?
  1. Extent Control Header  
  2. -----------------------------------------------------------------  
  3. Extent Header:: spare1: 0      spare2: 0      #extents: 1      #blocks: 8  
  4.                 last map  0x00000000  #maps: 0      offset: 2716  
  5.     Highwater::  0x01000189  ext#: 0      blk#: 8      ext size: 8   --Highwater就是高水位,0x01000189这个是HWM的地址  
  6. #blocks in seg. hdr's freelists: 0  
  7. #blocks below: 5  
  8. mapblk  0x00000000  offset: 0  
  9.                  Unlocked  
  10. --------------------------------------------------------  
  11. Low HighWater Mark :  
  12.     Highwater::  0x01000189  ext#: 0      blk#: 8      ext size: 8  
  13. #blocks in seg. hdr's freelists: 0  
  14. #blocks below: 5  
  15. mapblk  0x00000000  offset: 0  
  16. Level 1 BMB for High HWM block: 0x01000181  
  17. Level 1 BMB for Low HWM block: 0x01000181  
  18. --------------------------------------------------------  
  19. Segment Type: 1 nl2: 1      blksz: 8192   fbsz: 0  
  20. L2 Array start offset:  0x00001434  
  21. First Level 3 BMB:  0x00000000  
  22. L2 Hint for inserts:  0x01000182  
  23. Last Level 1 BMB:  0x01000181  
  24. Last Level II BMB:  0x01000182  
  25. Last Level III BMB:  0x00000000  
  26.    Map Header:: next  0x00000000  #extents: 1    obj#: 52713  flag: 0x10000000  
  27. Inc # 0  
  28. Extent Map  
  29. -----------------------------------------------------------------  
  30.  0x01000181  length: 8  
  31.   
  32. Auxillary Map  
  33. --------------------------------------------------------  
  34.  Extent 0     :  L1 dba:  0x01000181 Data dba:  0x01000184  
  35. --------------------------------------------------------  
  36.   
  37.  Second Level Bitmap block DBAs  
  38.  --------------------------------------------------------  
  39.  DBA 1:   0x01000182  
  40.   
  41. d dump data blocks tsn: 4 file#: 4 minblk 387 maxblk 387  




[sql] view plain copy
 print?
  1. --对t表做一次全表扫  
  2.   
  3. hr@ORCL> set autot traceonly  
  4. hr@ORCL> select * from t;  
  5.   
  6.   
  7. Execution Plan  
  8. ----------------------------------------------------------  
  9. Plan hash value: 1601196873  
  10.   
  11. --------------------------------------------------------------------------  
  12. | Id  | Operation         | Name | Rows  | Bytes | Cost (%CPU)| Time     |  
  13. --------------------------------------------------------------------------  
  14. |   0 | SELECT STATEMENT  |      |     1 |    20 |     3   (0)| 00:00:01 |  
  15. |   1 |  TABLE ACCESS FULL| T    |     1 |    20 |     3   (0)| 00:00:01 |  
  16. --------------------------------------------------------------------------  
  17.   
  18. Note  
  19. -----  
  20.    - dynamic sampling used for this statement  
  21.   
  22.   
  23. Statistics  
  24. ----------------------------------------------------------  
  25.           0  recursive calls  
  26.           0  db block gets  
  27.           7  consistent gets   --全表扫读了6个块  
  28.           0  physical reads  
  29.           0  redo size  
  30.         469  bytes sent via SQL*Net to client  
  31.         385  bytes received via SQL*Net from client  
  32.           2  SQL*Net roundtrips to/from client  
  33.           0  sorts (memory)  
  34.           0  sorts (disk)  
  35.           1  rows processed  

       这6个块是如何算出来的呢?



[sql] view plain copy
 print?
  1. hr@ORCL> select file_id,block_id,blocks from dba_extents where segment_name='T';  
  2.   
  3.    FILE_ID   BLOCK_ID     BLOCKS  
  4. ---------- ---------- ----------  
  5.          4        385          8  

       这t段一共用了8个块,分别是385 386 387 388 389 390 391 392 393
       Highwater::  0x01000189  即:4号文件的393号块
       这个可由下面dbms_utility包算出



[sql] view plain copy
 print?
  1. sys@ORCL> select to_number('01000189','xxxxxxxx') from dual;  
  2.   
  3. TO_NUMBER('01000189','XXXXXXXX')  
  4. --------------------------------  
  5.                         16777609  
  6.   
  7. sys@ORCL> select dbms_utility.data_block_address_file(16777609) from dual;  
  8.   
  9. DBMS_UTILITY.DATA_BLOCK_ADDRESS_FILE(16777609)  
  10. ----------------------------------------------  
  11.                                              4  
  12.   
  13. sys@ORCL> select dbms_utility.data_block_address_block(16777609) from dual;  
  14.   
  15. DBMS_UTILITY.DATA_BLOCK_ADDRESS_BLOCK(16777609)  
  16. -----------------------------------------------  
  17.                                             393  

       读了一次段头块:4号文件387号块
       读了高水位之下的388 389 390 391 392 等5个块
       这样一共就读了6个块
       注:
         385是FIRST LEVEL BITMAP BLOCK
         386是SECOND LEVEL BITMAP BLOCK
         
       接着分析我们所dump的内容:
     
[sql] view plain copy
 print?
  1. Low HighWater Mark :  
  2.     Highwater::  0x01000189  ext#: 0      blk#: 8      ext size: 8   

       
       接下来谈谈highwater mark 和 low highwater mark
       
       low high water mark与high water mark 之间可能存在formated block也可以可能存在unformatted block


       Oracle  降低高水位线的方法

       先来理清dba_tables里面的字段blocks的含义
       
       dba_tables.blocks记录的是分析得到的 formatted block 的总数
       而 low hwm 和 high hwm之间可能同时存在 formatted block 和 unfomatted block
       所以准确地说  blocks 不能代表 low hwm 或high hwm
       如果 low hwm 和 high hwm之间正好没有formatted block时,dba_tables.blocks和low hwm下的blocks一致
       
       那么什么是Oracle中未格式化的块呢?
       
       未格式化,意思就是这个块,已经是属于这个段了,但是还保留着原来的样子没动
       格式化就是把块中的数据清除掉,并把块头改为这个对象的
       MSSM表空间中的段,只有一个高水位,高水位下的块都是格式化了的
       但是ASSM表空间中的段,有两个高水位:低高水位和高高水位
       即上文trc里的:Highwater::  0x01000189和Low HighWater Mark Highwater::  0x01000189
       低高水位下的块全部是格式化了的
       但是低高水位和高高水位之间的块,则可能是格式化了的,也可能是没有
       
       现在的t的高高水位是file 4,block 393;其低高水位是file 4,block 393
       
       我们现在再来看一下t现在data_object_id是多少:


[sql] view plain copy
 print?
  1. hr@ORCL> select object_id,data_object_id from dba_objects where object_name='T';  
  2.   
  3.  OBJECT_ID DATA_OBJECT_ID  
  4. ---------- --------------  
  5.      52713          52714  

       这里很明显t的data_object_id大于object_id
       也就是说,在t上曾经发生过move或truncate操作
       注意,对于truncate操作而言,truncate后其data_object_id不一定就是在原先的data_object_id上加1



[sql] view plain copy
 print?
  1. sys@ORCL> select to_char('52714','XXXXXXXX') from dual;  
  2.   
  3. TO_CHAR('  
  4. ---------  
  5.      CDEA  

       换句话说,t中现在在其低高水位和其高高水位之间的block,只要这个block上记录的data_object_id不等于CDEA
       我们可以通过dump里面的Block header dump部分中的seg/obj来判断其data_object_id是否与段编号相等
       那么这个block 就是一个未格式化的块
       也就是说,可以通过data_object_id来确定块是在HWM和LHWM的位置
       
       那么Oracle为什么要增加低高水位设置?出于什么目的?全表扫描时,是到低高水位,还是到高高水位?
       
       Oracle设计有一个原则,就是把一个大操作分散到很多小操作中,以保证某个大操作不会花费太长时间
       无论是延迟提交,还是什么,都体现了这种思想,这和Linux的理念有异曲同工之妙哦
       而低高水位线与高高水位线结合,正是这种思想的体现
       可以不用一次性格式化所有新分配的块,留一部分给下次操作来完成
       
       全表扫描时,通常都是读至低高水位线,然后根据位图去读低高与高高之间格式化过的块,避开未格式化的块
     
       如何查看HWM?如何知道HWM下有多少空闲的空间?

       
       最实用的方法就是dump segment_header,速度快,而且对应用没有影响
       而且,trc里面的"#blocks in seg. hdr's freelists:"可以告诉我们HWM下有多少空闲块
       这里需要注意,如果dba_segments.freelist_groups > 1,那么freelist不再segment header中
       比如,freelist_group = 3 ,则你便要分别dump header后面的3个块,来看每个group的freelist的个数
       
       那么如何降低HWM呢?
        
       ① expdp/impdp
       ② 10G及以后的版本可以采用shrink,需要注意的是,表所在表空间须为自动段空间管理
          alter table tab_name enable row movement;
          alter table tab_name shrink space;
       ③ 使用move,不过在Move期间,会影响到DML语句,如UPDATE,也需要考虑空间问题
          总之move会锁表 而且是TM  另外还会影响index,所以,之后记得rebuild index
          alter table move tab_name;  在当前表空间中move
          alter table move tab_name tablespace tbs_name;  将其move到其他表空间
       ④ CTAS  然后rename,rebuild index
       ⑤ 在线重定义


        等等.......





高水位(High Water Mark)的概念及高水位问题的解决

说到HWM,我们首先要简要的谈谈ORACLE的逻辑存储管理.我们知道,ORACLE在逻辑存储上分4个粒度:表空间,段,区和块. 
 
(1)块:是粒度最小的存储单位,现在标准的块大小是8K,ORACLE每一次I/O操作也是按块来操作的,也就是说当ORACLE从数据文件读数据时,是读取多少个块,而不是多少行. 
 
(2) 区:由一系列相邻的块而组成,这也是ORACLE空间分配的基本单位,举个例子来说,当我们创建一个表PM_USER时,首先ORACLE会分配一区的空 间给这个表,随着不断的INSERT数据到PM_USER,原来的这个区容不下插入的数据时,ORACLE是以区为单位进行扩展的,也就是说再分配多少个 区给PM_USER,而不是多少个块.  
 
(3) 段:是由一系列的区所组成,一般来说,当创建一个对象时(表,索引),就会分配一个段给这个对象.所以从某种意义上来说,段就是某种特定的数据.如 CREATE TABLE PM_USER,这个段就是数据段,而CREATE INDEX ON PM_USER(NAME),ORACLE同样会分配一个段给这个索引,但这是一个索引段了.查询段的信息可以通过数据字典: SELECT * FROM USER_SEGMENTS来获得,
 
(4)表空间:包含段,区及块.表空间的数据物理上储存在其所在的数据文件中.一个数据库至少要有一个表空间.
 
OK,我们现在回到HWM上来,那么,什么是高水位标记呢?这就跟ORACLE的段空间管理相关了.
 
 
(一)ORACLE用HWM来界定一个段中使用的块和未使用的块.


举 个例子来说,当我们创建一个表:PT_SCHE_DETAIL时,ORACLE就会为这个对象分配一个段.在这个段中,即使我们未插入任何记录,也至少有 一个区被分配,第一个区的第一个块就称为段头(SEGMENT HEADE),段头中就储存了一些信息,基中HWM的信息就存储在此.此时,因为第一个区的第一块用于存储段头的一些信息,虽然没有存储任何实际的记录, 但也算是被使用,此时HWM是位于第2个块.当我们不断插入数据到PM_USER后,第1个块已经放不下后面新插入的数据,此时,ORACLE将高水位之 上的块用于存储新增数据,同时,HWM本身也向上移.也就是说,当我们不断插入数据时,HWM会往不断上移,这样,在HWM之下的,就表示使用过的 块,HWM之上的就表示已分配但从未使用过的块.
 
(二)HWM在插入数据时,当现有空间不足而进行空间的扩展时会向上移,但删除数据时不会往下移.
 
这就好比是水库的水位,当涨水时,水位往上移,当水退出后,最高水位的痕迹还是清淅可见.
考虑让我们看一个段,如一张表,其中填满了块,如图 1 所示。在正常操作过程中,删除了一些行,如图 2 所示。现有就有了许多浪费的空间:(I) 在
新闻标题:Oracle降低高水位线的方法
转载来源:http://hbruida.cn/article/jcjics.html