Oracle delete操做隐藏着你可能不知道的秘密

现象描述web

Deleteoracle数据库中的经常使用操做,尤为是在自动化测试中,初始化环境、前置准备都不可避免的进行增删操做,但持续一时间后,可能会碰到表空间不足这类报错现象,这就不由纳闷儿了,明明插入数据前会有删除的,数据总量并无呈现明显的量级变化,为何表占用空间却在偷偷增大呢?数据库

 

现象分析oracle

出现上述现象的缘由是Delete操做并不会释放占用的空间。在讲解缘由以前,先了解下oracle中高水位线的概念,有助于理解delete操做产生的这种现象。app

所谓的高水位(HWM),通俗的讲就是一个标记,用来记录已经有多少数据块(Block)分配给表,能够拿水库的历史最高水位来类比,当使用delete操做后,数据虽然被删除了,但这个高水位的标记并无下降,就比如水库的历史最高水位不会由于水被释放了而下降。于是,原则上在没有外部干预的条件下,这个高水位标记值只会增大,不会下降。ide

 

实战模拟重现现象测试

根据上面的现象描述和分析,接下来,我会用具体的实例模拟该现象,使你们能够更直观的了解。spa

1,建立一张测试表test,具体字段不须要关心,只要知道初始了存储空间为100M,如图所示:3d

1.jpg 


2,建立完成后,咱们查看下数据表占用的空间,如图所示:orm

 2-记住三个关键数据.jpg


其中,查询前须要对表进行分析,使用命令为:ANALYZE TABLE test ESTIMATE STATISTICS;查询语句为:SELECT blocks, empty_blocks, num_rows FROM user_tables WHERE table_name = 'TEST';blog

注意上面三个字段的结果:BLOCKS=0;  EMPTY_BLOCKS=13312;  NUM_ROWS=0,即当前表占用的块数为0,默认1 BLOCK = 8kb,预分配的块为13312,行数为0

一切都没有问题,新建立的表,没有数据嘛,固然行数为0,占用块数为0喽。

 

3,写一个语句块,循环插入1000条语句,再次对test表进行分析、查询,结果以下:

3插入数据.jpg


 

从图中能够看到,占用BLOCKS=222NUM_ROWS=1000,合乎逻辑,插入了1000条数据,占用了空间嘛。

 

4,使用Delete语句删除1000条数据,再次对test表进行分析、查询,结果倒是以下:

4删除后行数为0空间还占用.jpg


从上图中能够清楚的看到,数据被删除后,NUM_ROWS=0了,可是BLOCKS并无被置为0,也就是这部分数据块仍然被认为是占用的。

所以,就出现了本文一开始就提到的现象,随着不断的插入、删除数据,BLOCKS也会不断扩大,尽快delete操做后,可能表中数据量不多,但表占用的存储空间未减小。

 

解决方法

针对delete操做引发的空间不释放现象,或者,更正式一点的说法,如何下降高水位线,方法有不少种,如,shrink spacemove tablespacecreate table xxx as select * from xxx 重建表等。使用这些方法前,咱们的原则是:

若是能够truncate,直接truncate,该操做会重置高水位线,BLOCKS会被置为0NUM_ROWS置为0;不然,优先使用shrink space,该方法不须要重建索引。

接着上面第4步,咱们使用shrink space下降高水位线,释放空间,其中,使用shrink space命令前,须要先alter table test enable row movement;开启行移动,再次对表进行分析、查询,结果以下:

 5.jpg

 

从图中能够看出,此时BLOCKS已经被置为0了,可是,细心的你可能也发现, EMPTY_BLOCKS已经不是初始的13312,而是此时的40,这说明shrink space不只会释放高水位线如下的空间,也会释放申请的空间,即高水位线上下都有操做,这也是与movetruncate的不一样,它们只能释放高水位线如下的空间。

 

shrink space经常使用操做命令

Shrink space的经常使用命令以下:

6 经常使用命令.jpg

 

Delete操做的潜在影响

根据上述分析,delete操做产生的潜在影响以下:

1. 全表扫描一般要读出直到HWM标记的全部属于该表的数据块,即便该表中没有任何数据;(形成查询变慢)

2. 插入操做时使用append关键字,即便HWM如下有空闲的数据库块,插入时使用HWM以上的数据块;(形成HWM自动增大)

 

总结

经过上文的现象描述和分析,随着insert的不断操做,高水位线也随着不断增长,尽管delete了数据,但高水位线并无降低,致使表占用的空间没有释放。所以,在实际应用中,若是可能,尽可能使用truncate,并且该操做高效、快速;不然要考虑下delete操做遗留的影响,使用合适的方法整理空间。