1.1 概述
高水位线(high-water mark,HWM
) 在数据库中,如果把表想象成从左到右依次排开的一系列块,高水位线就是曾经包含了数据的最右边的块,高水位就是用来标明我以往使用过的块数的最高位。原则上HWM
只会增大, 即使将表中的数据全部删除,HWM
也不会降低。
HWM
不是好事,查询时要扫描表的块,不是扫描表分配了多少块,而是高水位线以下的所有数据块。全表扫描时通常要读出HWM
以下的所有数据块(尽管该表中可能仅有少量数据),这将占用大量IO
资源.
1.2 降低 HWM 的方法
1.2.1 Rebuild
复制要保留的数据到临时表 t,drop
原表,然后rename
临时表 t 为原表。
1.2.2 Exp Imp
1.2.3 Move
将表从一个 TBS 移动到另一个 TBS (也可以在本 TBS 内move
),可以清除表里的碎片。
# 语法:alter table t1 move [tablespace users];# move后不跟TBS说明还是原来的空间优点:可以清除数据块中的碎片,降低高水位线。缺点:move需要额外 (一倍) 的空间move过程中会锁表,其他用户不能在该表上做DML或DDL操作。move之后,相关索引都不可用了,表上的索引需要重建。
1.2.4 Truncate
采用TRUNCATE
语句删除一个表的数据的时候,类似于重新建立了表,不仅把数据都删除了,还把HWM
给清空恢复为 0。所以如果需要把表清空,在有可能利用TRUNCATE
语句来删除数据的时候就利用TRUNCATE
语句来删除表,特别是那种数据量有可能很大的临时存储表。
1.2.4.1 创建表
scott:SQL> drop table t purge;SQL> create table t(id number) SEGMENT CREATION IMMEDIATE;-- 11gR2的新特性,默认延迟段创建,所以immediate,立即分配段-- 此时表没有分析,是原始的数据,即8个数据块(分配最小存储空间一个区, 初始大小是64K,一个标准块的大小是8K,刚好是8个BLOCK)-- sys查看dba表SQL> SELECT segment_name,segment_type,blocks FROM dba_segments WHERE segment_name='T';SEGMENT_NAME SEGMENT_TYPE BLOCKS------------ ------------ ---------T TABLE 8-- scott查看user表SQL> col table_name format a10SQL> SELECT table_name,num_rows,blocks,empty_blocks FROM user_tables WHERE table_name='T';TABLE_NAME NUM_ROWS BLOCKS EMPTY_BLOCKS----------------- ---------------- ---------- ------------------T
1.2.4.2 插入数据
SQL>declarei number;beginfor i in 1..10000 loopinsert into t values(i);end loop;commit;end;/PL/SQL procedure successfully completed.
1.2.4.3 再次查看表的信息
-- sys查看dba表SQL> SELECT segment_name,segment_type,blocks FROM dba_segments WHERE segment_name='T';SEGMENT_NAME SEGMENT_TYPE BLOCKS------------ ------------ ------T TABLE 24-- scott查看user表SQL> col table_name format a10SQL> SELECT table_name,num_rows,blocks,empty_blocks FROM user_tables WHERE table_name='T';TABLE_NAME NUM_ROWS BLOCKS EMPTY_BLOCKS----------------- ---------------- ---------- ------------------T-- 此时表T 占用的数据库已经是24个了. 但是user_tables 显示的信息还是为空。因为没有做统计分析。
1.2.4.4 使用包收集统计信息
-- scottSQL> exec DBMS_STATS.GATHER_TABLE_STATS('scott','T');PL/SQL procedure successfully completed.SQL> SELECT table_name,num_rows,blocks,empty_blocks FROM user_tables WHERE table_name='T';TABLE_NAME NUM_ROWS BLOCKS EMPTY_BLOCKS--------- -------- ------ -------------T 10000 20 0
此时user_tables
已经有了数据,显示的使用了 20 个数据块。但是empty_blocks
还是为空。这里要注意的地方。这个字段只有使用analyze
收集统计信息之后才会有数据。
1.2.4.5 analyze 收集统计信息
SQL> ANALYZE TABLE T COMPUTE STATISTICS;Table analyzed.SQL> SELECT table_name,num_rows,blocks,empty_blocks FROM user_tables WHERE table_name='T';TABLE_NAME NUM_ROWS BLOCKS EMPTY_BLOCKS---------- -------- ------- ------------T 10000 20 4
1.2.4.6 delete 数据不会降低 HWM
SQL> delete from t;10000 rows deleted.SQL> commit;Commit complete.SQL> analyze table t compute statistics;Table analyzed.SQL> SELECT segment_name,segment_type,blocks FROM dba_segments WHERE segment_name='T';SEGMENT_NAME SEGMENT_TYPE BLOCKS------------ ------------ -------T TABLE 24SQL> SELECT table_name,num_rows,blocks,empty_blocks FROM user_tables WHERE table_name='T';TABLE_NAME NUM_ROWS BLOCKS EMPTY_BLOCKS---------- -------- ------- ------------T 10000 20 4
1.2.4.7 truncate 表可以降低 HWM
SQL> truncate table t;Table truncated.SQL> SELECT segment_name,segment_type,blocks FROM dba_segments WHERE segment_name='T'; -- 已经改变TABLE_NAME NUM_ROWS BLOCKS EMPTY_BLOCKS---------- -------- ------- ------------T TABLE 8SQL> SELECT segment_name,segment_type,blocks FROM dba_segments WHERE segment_name='T'; -- 需要收集统计信息TABLE_NAME NUM_ROWS BLOCKS EMPTY_BLOCKS---------- -------- ------- ------------T 10000 20 4DBMS_STATS包收集统计信息SQL> exec DBMS_STATS.GATHER_TABLE_STATS('scott','T');SQL> SELECT segment_name,segment_type,blocks FROM dba_segments WHERE segment_name='T'; -- 需要analyze收集统计信息TABLE_NAME NUM_ROWS BLOCKS EMPTY_BLOCKS---------- -------- ------- ------------T 10000 0 4SQL> ANALYZE TABLE T COMPUTE STATISTICS;SQL> SELECT segment_name,segment_type,blocks FROM dba_segments WHERE segment_name='T';TABLE_NAME NUM_ROWS BLOCKS EMPTY_BLOCKS---------- -------- ------- ------------T 10000 0 8
1.2.5 Shrink
收缩表,也叫段重组
:表收缩的底层实现的是通过匹配的INSERT
和DELETE
操作。它分两个不同的阶段:压缩阶段和 DDL 命令阶段。
-- 语法:alter table t2 shrink space [cascade][compact];alter table <table_name> shrink space [ <null> | compact | cascade ];
发出alter table t2 shrink space compact;
那么只完成了第一阶段。这是压缩阶段。在业务高峰时可以先完成第一阶段,高峰过后,再次alter table t2 shrink space;
因压缩阶段工作大部分已完成,将很快进入第二阶段,DML 操作会有短暂的锁等待发生。
测试:
1.2.5.1 建立表和表空间
-- sys:SQL> create tablespace klaus datafile '/u01/app/oracle/oradata/orcl/klaus01.dbf' size 100m;SQL> create table scott.t2 tablespace klaus as select * from dba_objects;
1.2.5.2 查看表信息
-- scott:SQL> select max(rownum) from t2;MAX(ROWNUM)--------------------91923SQL> select table_name, blocks, empty_blocks, num_rows from user_tables where table_name='T2';TABLE_NAME BLOCKS EMPTY_BLOCKS NUM_ROWS--------- ------ ------------ ---------T2 1578 0 91923
1.2.5.3 analyze 收集统计信息
SQL> analyze table t2 compute statistics;
1.2.5.4 删除数据
SQL> delete t2 where rownum<=40000;SQL> commit;
1.2.5.5 再次 analyze 收集统计信息
SQL> analyze table t2 compute statistics for table;SQL> select table_name, blocks, empty_blocks, num_rows from user_tables where table_name='T2';TABLE_NAME BLOCKS EMPTY_BLOCKS NUM_ROWS--------- ------ ------------ ---------T2 1578 0 51923-- 这时候,num_rows已经减掉了40000条, 但 blocks 并没有减少, 说明HWM没有下降.
1.2.5.6 Shrink 前提-使能行移动
SQL> alter table t2 enable row movement;
1.2.5.7 shrink 第一步-压缩阶段 -HWM 不会降低
SQL> alter table t2 shrink space compact;SQL> analyze table t2 compute statistics for table;SQL> select table_name, blocks, empty_blocks, num_rows from user_tables where table_name='T2';TABLE_NAME BLOCKS EMPTY_BLOCKS NUM_ROWS--------- ------ ------------ ---------T2 1578 0 51923
1.2.5.8 shrink 第二步-DDL命令阶段 -HWM 降低
SQL> alter table t2 shrink space;SQL> analyze table t2 compute statistics for table;SQL> select table_name, blocks, empty_blocks, num_rows from user_tables where table_name='T2';TABLE_NAME BLOCKS EMPTY_BLOCKS NUM_ROWS--------- ------ ------------ ---------T2 888 0 51923-- HWM已经降低.




