Oracle HWM
什么是HWM
所有的oracle segments都有一个在段内容纳数据的上限,我们把这个上限称为HWM(High Water Mark)。这个HWM是一个标记,用来说明已经有多少没有使用的数据块分配给这个segment。HWM通常增长的幅度为一次5个数据块,原则上HWM只会增大,不会缩小,即使将表中的数据全部删除,HWM还是为原值,由于这个特点,使HWM很象一个水库的历史最高水位,这也就是HWM的原始含义,当然不能说一个水库没水了,就说该水库的历史最高水位为0。但是如果我们在表上使用了truncate命令,则该表的HWM会被重新置为0。
在手动段空间管理(Manual Segment Space Management)中,段中只有一个HWM,但是在Oracle9i添加的自动段空间管理(Automatic Segment Space Management)中,当数据插入以后,如果是插入到新的数据块中,数据块就会被自动格式化等待数据访问。而在自动段空间管理中,数据插入到新的数据块以后,数据块并没有被格式化,而是在第一次在第一次访问这个数据块的时候才格式化这个块。所以又多出一条水位线,用来标示已经被格式化的块。这条水位线就叫做低HWM。一般来说,低HWM肯定是低于等于HWM。
HWM的影响
HWM的用途
在使用select语句会对表中的数据进行一次扫描,Oracle会扫描高水位线以下的数据块。也就是说新建的一张表,进行了一次select操作,那么由于高水位线HWM在最低的0位置上,所以没有数据块需要被扫描,扫描时间会极短。如果该表中已经被插入大量的数据,随后这些数据被delete。由于插入了数据,由于delete语句不影响高水位线,所以这个时候的高水位线就在这些数据这里。这个时候再一次用select语句进行扫描,虽然这个时候表中没有数据,但是由于扫描是按照高水位线来的,需要把这些数据的存储空间都要扫描一次。HWM数据库的操作有如下影响
1、全表扫描通常要读出直到HWM标记的所有的属于该表数据库块,即使该表中没有任何数据。
2、即使HWM以下有空闲的数据库块,键入在插入数据时使用了append关键字,则在插入时使用HWM以上的数据块,此时HWM会自动增大。
测试一下
创建一个测试表
SQL> create table test(id number(4,0),test varchar2(10)) tablespace users;
Table created.
此时表中没有数据,通过user_tables和user_segments来查看一下表中数据块的使用情况
SQL> col segment_name for a20
SQL> select segment_name,segment_type,blocks,bytes from user_segments where segment_name='TEST';
SEGMENT_NAME SEGMENT_TYPE BLOCKS BYTES
-------------------- ------------------ ---------- ----------
TEST TABLE 8 65536
这里的BLOCKS指的是该表初始化segment的大小
使用analyze 收集统计信息
SQL> analyze table test compute statistics;
Table analyzed.
SQL> select table_name,num_rows,blocks,empty_blocks from user_tables where table_name='TEST';
TABLE_NAME NUM_ROWS BLOCKS EMPTY_BLOCKS
--------------- ---------- ---------- ------------
TEST 0 0 8
也就是说现在分给给test表的8个数据库都处于空闲状态
插入测试数据
SQL> begin
2 for i in 1..10000 loop
3 insert into test
4 values(round(dbms_random.value(0,10000)),dbms_random.string('u',5));
5 end loop;
6 commit;
7 end;
8 /
PL/SQL procedure successfully completed.
SQL> select count(*) from test;
COUNT(*)
----------
10000
再次查看此时的segment分配信息,已经非配32个block
SQL> select segment_name,segment_type,blocks from user_segments where segment_name='TEST';
SEGMENT_NAME SEGMENT_TYPE BLOCKS
-------------------- ------------------ ----------
TEST TABLE 32
SQL> analyze table test compute statistics;
Table analyzed.
SQL> select table_name,blocks,empty_blocks from user_tables where table_name='TEST';
TABLE_NAME BLOCKS EMPTY_BLOCKS
--------------- ---------- ------------
TEST 28 4
segment和tables中的block对应关系如下
user_segment.blocks=user_tables.blocks+user_tables.empty_blocks+1
其中
user_tables.blocks列代表该表中曾经使用过得数据库块的数目,即水线。
user_tables.empty_blocks代表分配给该表,但是在水线以上的数据库块,即从来没有使用的数据块。
1是指多出的一个数据块用保留来做segment header
使用delete 删除表中数据,将会发现表中数据的水线并未降低
SQL> delete from test;
10000 rows deleted.
SQL> commit;
Commit complete.
SQL> select segment_name,segment_type,blocks from user_segments where segment_name='TEST';
SEGMENT_NAME SEGMENT_TYPE BLOCKS
-------------------- ------------------ ----------
TEST TABLE 32
SQL> analyze table test compute statistics;
Table analyzed.
SQL> select table_name,blocks,empty_blocks from user_tables where table_name='TEST';
TABLE_NAME BLOCKS EMPTY_BLOCKS
--------------- ---------- ------------
TEST 28 4
使用shrink收缩表
SQL> alter table test enable row movement;
Table altered.
SQL> alter table test shrink space cascade;
Table altered.
SQL> select segment_name,segment_type,blocks from user_segments where segment_name='TEST';
SEGMENT_NAME SEGMENT_TYPE BLOCKS
-------------------- ------------------ ----------
TEST TABLE 8
SQL> analyze table test compute statistics;
Table analyzed.
SQL> select table_name,blocks,empty_blocks from user_tables where table_name='TEST';
TABLE_NAME BLOCKS EMPTY_BLOCKS
--------------- ---------- ------------
TEST 1 7
回收HWM
1、使用move移动表
SQL> alter table test move;
Table altered.
SQL> alter table test move tablespace users;
Table altered.
2、如上面测试中的方法,使用shrink来收缩表
3、可以的情况下重建表
4、使用alter table table_name deallocate unused
DEALLOCATE UNUSED为释放HWM上面的未使用空间,但是并不会释放HWM下面的自由空间,也不会移动HWM的位置.
5、不重要的数据被删除,或者确定该表中数据不需要闪回的情况下尽量使用truncate删除数据。