索引rebuild和coalesce操作的比较
虽然大多数情况下,我们并不需要重建索引,来回收索引中的碎片空间,让索引的访问更高效。但是,对于一些特定的情况,比如有较多且较大空闲空间的叶子块,且很少有适合的索引条目被插入,可能导致大量空间浪费;或者经历了一次大量数据的删除后,希望减少因此而导致的索引访问效率不佳的问题,而需要重建索引时。我们通常会有两种重建索引的方法:alter index xxx rebuild和alter index xxx coalesce。
Rebuild的方式,加排它锁,会让单个索引块内的可用空间尽可能少,整个索引所需的索引块更少,高度更低。通常,在索引中的碎片空间超过三分之一时,Rebuild期间产生的REDO更少,但它需要额外的临时空间以完成这一操作。
Coalesce的方式,无排它锁,仅在叶子块层级做合并,不会降低索引高度,但会减少叶子块的数量。通常,在索引中的碎片空间低于三分之一时,coalesce期间产生的REDO会更少,且操作期间不需要额外的临时空间。
下面,我们还是通过实验,来观察一下这两种重建索引的方式的主要差异:
我们使用类似误区1中的实验环境创建方法,创建一个三层的索引:
图 165
查看该索引的树形结构信息:
图 166
如上图所示,我们可以看到该索引是一个三层高的索引。主要叶子节点都集中在第一个分支块上。第一个分支块下有16个叶子块,每个叶子块中有13条索引条目。
1 无碎片空间时两种重建方式的对比
接下来,我们在索引中并没有所谓“碎片”空间的情况下,分别用rebuild和coalesce的方法重建该索引,观察相关操作消耗的资源开销(逻辑读,REDO和UNDO)。
图 167
如上图所示,使用REBUILD方式时,其逻辑读的消耗是289(1228-939)块次,REDO的产生量是175444(494756-319312)字节,UNDO的产生量是4528(17852-13324)字节。
再来看看REBUILD后,索引的结构是否有了变化呢?
图 168
如上图所示,索引的结构没有变化,依然是三层,2个分支块,17个叶子块,其中16个叶子块在第一个分支块上。但是,我们可以发现,所有的索引块都已经和之前的,没有一个是重复的。即,REBUILD方式,是在另一块存储空间,把原索引重建了一遍。
我们再来看一下使用COALESCE方式时,其表现又是什么样子。
为了避免干扰,我们重新创建相关索引,并使用COALESCE的方式来操作。
此时新建的索引树形结构信息如下:
图 169
我们进行COALESCE的操作,并查看其资源开销:
图 170
如上图所示,使用COALESCE方式时,其逻辑读的消耗是38(156-118)块次,REDO的产生量是1076(5400-4324)字节,UNDO的产生量是80(536-456)字节。明显比REBUILD的开销要小。
继续查看COALESCE处理后,其索引的树形结构信息:
图 171
我们可以看到COALESCE操作前后,索引块的编号及其在索引中的位置是一模一样的。没有变化。
2 30%碎片空间时两种重建方式的对比
下面,我们尝试模拟索引中有约30%的索引条目被删除后,用不同的重建方式,其资源开销的情况:
图 172
如上图所示,使用REBUILD方式时,其逻辑读的消耗是243(787-544)块次,REDO的产生量是120624(223580-102956)字节,UNDO的产生量是4104(81624-77520)字节。
此时,索引的树形结构信息如下:
图 173
如上图所示,索引目前变为了2层的高度。只有1个根块和12个叶子块了。
再来看下COALESCE方式。重建相关索引,并删除30%的记录:
图 174
进行COALESCE的操作,并是查看相关开销:
图 175
如上图所示,使用COALESCE方式时,其逻辑读的消耗是143(2287-2154)块次,REDO的产生量是230380(878116-647736)字节,UNDO的产生量是138460(314320-175860)字节。
此时,索引的树形结构信息如下:
图 176
如上图所示,索引的高度没变,分支块没有减少。但第一个分支块下的叶子块,由删除前的16个叶子块,变为12个叶子块。
3 60%碎片空间时两种重建方式的对比
重建表和索引,并删除其中约60%的索引后,观察REBUILD方式的开销:
图 177
查看REBUILD方式的资源开销:
图 178
如上图所示,使用REBUILD方式时,其逻辑读的消耗是238(4171-3933)块次,REDO的产生量是76896(14772244-1395348)字节,UNDO的产生量是4104(488428-484324)字节。
此时,索引的树形结构信息如下:
图 179
如上所示,索引变为了2层高,叶子块减少到7个。
同前,再次重建表和索引,并删除其中约60%的索引后,观察COALESCE方式的开销:
图 180
如上图所示,使用COALESCE方式时,其逻辑读的消耗是194(4171-3933)块次,REDO的产生量是268260(1244492-976232)字节,UNDO的产生量是180716(684516-503800)字节。
此时,索引的树形结构信息如下:
图 181
如上图所示,索引的高度没有变化,依然是3层,但叶子块减少了。
4 总结
我们将三种情形下的两种重建方式的资源开销和索引层高的变化,汇总到如下表格中:
如上表所示,我们可以发现如下规律:
- 从逻辑读(logical reads)上来看,对于REBUILD方式,无碎片时最多,碎片越多,逻辑读越小。其原因应是重建后的索引需要的索引块越来越少所致;对于COALESCE方式,逻辑读正好相反,无碎片时最小,碎片越多,逻辑读越多。其原因应是碎片越多,需要处理的块越多所致。
- 从redo size上来看,对于REBUILD方式,无碎片时最多,碎片越多,redo size越小。其原因也应是重建后的索引需要的索引块越来越少所致,即修改的量在不断减少;对于COALESCE方式,redo size正好相反,无碎片时最小,碎片越多,逻辑读越多。其原因也应是碎片越多,需要修改的块越多所致。
- 从undo size上来看,对于REBUILD方式,无论碎片多少,其消耗基本持平。其原因应是新索引是向新块中插入数据,所以,需要的UNDO量很少。而对于COALESCE方式,undo sizer的消耗与碎片的多少成比,碎片越多,undo size越多。其原因也应是碎片越多,需要处理的块越多所致。
综上,从资源开销上说,当碎片较小时,使用COALESCE会消耗更少,而当碎片不断增加,COALESCE的开销会越来越大;而REBUILD方式则正相反,碎片越多,其需要的资源会越来越小。
此外,从索引层高上,我们也会现,REBUILD是重新紧密排列索引,会导致索引高度降低;而COALESCE则只在叶子块层重新紧密排列,并不会导致索引高度降低。因此,对于表中的数据大量减少后,又会很快增加记录的表,使用COALESCE的方式重建索引,会减少分支和根块的分裂次数,有利于减少争用。但此情况时,因为删除了大量数据,索引中的碎片必然较多,使用COALESCE会导致操作期间的资源开销较大。如果表中的数据大量减少后,数据增加得较慢,那么使用REBUILD方式来重建索引时,开销会比较少,同时由于增长较慢,索引的分裂导致的负面影响也会相对轻得多。至于用哪一种方式更好,则需要根据具体需求和环境条件来做出最终的选择。