最近整理了一下系统内所有表的空间占用情况,发现其中一些表其实只有及万行,却占用了非常大的空间,那么显而易见,这个表的“碎片”实在是太多了。
最开始接触oracle的时候我认为删除数据就是delete,但是后来的学习中,发现事情并不是我想象的那么简单,delete之后,系统也只是将这部分数据块置为可写状态,而实际上还是将这部分空间交由表来占用。而我发现我们系统中为了提高插入的效率,大量的使用了append方式,这样就更加积重难返了。
可以设计下面的实验:
有两个表test1和test2。
create table test1 as select * from dba_objects;create table test2 as select * from dba_objects;delete from test1;commit;delete from test2;commit;insert /*+append*/ into test1 select * from dba_objects;commit;insert into test2 select * from dba_objects;commit;
这样子,test1里就会有“碎片”了,而TEST2则是一个比较健康的表。占用空间为test1:17M,TEST2:9M。
现在就可以对比对比执行计划了:
analyze table test1 compute statistics;analyze table test2 compute statistics;
一样大的两张表,执行计划却有比较大的差异,在这种小数据量的情况下尚能看出差异,那么在生产系统中动辄上百万千万的数据量,这个效率差异会更加明显。
这些表在我们的系统中会每天都被delete一次,delete的效率也严重的被“碎片”影响着:
delete * from test1;
delete * from test2;
其实这个和上面的select是一样的,都是全表扫描,索引COST基本上和刚才的select语句一样。
这里写到的东西大部分在这里都写过了,这里就想说明一下对delete也有影响,也顺便在后面说几句shrink。
以前单位的总部曾经来过一个专家给我们指导过工作,告诉我们,有些表应该shrink一下了。之前已经说了,shrink的好处就是不会改变rowid,所以索引不会失效。还是刚才的test1,加上索引,进行shrink操作:
alter table test1 enable row movement;alter table test1 shrink space;
这样操作之后test1占用的空间就只有8.25M,再看看索引的状态:VALID。这是个很不错的消除表“碎片”的办法,值得在以后的工作中使用之。