什么是高水位线?
所有的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
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前:
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