在和运维兄弟们讨论新系统运维规划的时候,聊到了关于索引定期rebuild的问题。本篇也想发表一点笔者的拙见。
索引index是数据库表进行优化搜索的对象。索引与数据库表的索引列取值在叶子节点上相对应,提供更为高效的搜索执行计划。索引的一个特性就是与数据表索引列的结构数据相对应。江湖上流传,随着数据表的增删改操作,索引结构会呈现一种退化degrade趋势,此时就需要定期进行索引的重建rebuild,来恢复索引的高效特性。
1、 Why to rebuild
索引结构本身是一个平衡B*树,随着对应数据表行的增加修改和删除操作,索引叶子节点会连带发生变化,从而引起索引段结构的分裂、空置等变化。索引段index segment自身是一个不容易发生缩进的结构,所以索引本身呈现一个不断胀大臃肿的趋势。在对数据表进行DML操作的时候,索引树要连带进行变化。
ü 当进行insert操作时,一个非空的索引列值要插入到索引树结构中,作为一个新的叶子节点。在这个过程中,Oracle要保证索引树始终是平衡结构,要进行逻辑层面的分支节点分割,重新平衡过程。同时要进行物理块的分割,保持叶子块的相对宽松;
ü 当进行update操作时,Oracle索引同样要进行一次delete和insert相同的操作;
ü 当进行delete操作时,索引并不是将叶子节点回收,而是进行标记操作;
所以,对于一个经常进行DML操作的数据表而言,索引结构中往往包括了很多死叶子节点和分配未使用的空间。这种索引在表现上体现为数据行和索引对应块数量的不匹配。那么,仅仅因为这样的索引,就需要我们经常性的进行索引rebuild。对索引进行瘦身处理吗?
从Oracle官方[MOS ID 989093.1]的角度看,周期性的index rebuild操作,将其作为日常运维的一部分是不必要的。通常而言,进行B*树索引rebuild的场景是很少的,索引结构自身就是一个“self-managed, self-balanced”的结构。
通常我们认为索引需要经常性的rebuild,是基于下面的理由:
ü 频繁的DML操作,引起index结构碎片化;
ü 索引段index segment结构膨胀,删除deleted的叶子节点不会自己回收;
ü 聚簇因子clustering factor恶化;
事实上,在正常的DML操作下,索引结构是可以维持在一个相对臃肿的结构下。删除的叶子节点的确会造成空间的浪费和检索成本提高,但是删除叶子节点是可以为下一次的insert/update操作所重用。而且被删除的叶子节点遍布整个叶子列表,为新数据值的插入提供了相当容纳空闲空间。也就是说,虽然索引适度臃肿,但是这种臃肿不是空间的浪费,而是可被再次利用的。
聚簇因子衰弱的确是一个严重影响执行计划的重要指标。但是聚簇因子的衰弱并不是由于索引结构自身问题,而是由于数据表行排序顺序的混乱造成的。解决聚簇因子退化的方法,是进行数据表重构,而非rebuild索引结构(关于clustering facter的相关内容,请参考笔者《Clustering Factor——索引的成本指标》http://space.itpub.net/17203031/viewspace-680936)。
综合上述,笔者认为,正常DML情况下,周期性的对所有Index进行rebuild操作是不需要的。在数据表数据量维持稳定的情况下,适度臃肿的索引结构是我们可以接受的现实。
2、Why not to rebuild
那么,如果我们执意进行索引结构的定期rebuild,会带来哪些风险呢?
首先,rebuild日常作业化容易带来系统维护窗口的争用。当我们进行rebuild索引结构时,给系统带来一定程度的性能损耗和空间消耗。Rebuild索引必然会影响到前端业务系统的运行,选择维护窗口期回避业务高峰是唯一可以进行的折中。于是,rebuild又会影响到其他如统计量收集等更为重要的维护操作。
其次,重建的紧凑tight索引结构也许并不是适应DML操作的结构。紧凑的叶子节点意味着日后的DML操作要消耗很多资源来进行叶子块拆分,空闲Free可用空间腾置。这对于“千辛万苦”才培养成的适度臃肿的索引结构,是一个浪费。
最后,主流检测索引语句的性能机制有问题。大部分检测索引健康程度是建立在index_stats视图下,使用analyze index XXX validate structure语句。但是这种方式在分析锁的时候要获取独占表table锁。这是一个潜在的性能瓶颈。
综合而言,确定日常性的索引rebuild操作是需要慎重的。要仔细进行分析和探讨,做到消耗最少的资源,实现最优的效果。最起码要做到索引的健全管理,有差异的rebuild。
3、what to rebuild
那么,究竟什么类型的索引需要进行索引定期rebuild呢?笔者认为,真正需要进行定期索引rebuild的索引在数量上是不多的,具体来说包括下面几个类型。
ü 索引列呈现单向递增顺序,且DML频繁,叶子节点空值重用率低的索引结构
我们上面的讨论,有一个重要的思想,就是DML适度频繁造成的索引叶子节点空值是不可怕的。因为叶子节点空值平均分布在索引树的叶子块上,当有新的数据值来时,这些空值是可以被重用的。但是,一些索引列的变化呈现单向增长趋势,如sequence列。索引列的新增数值都是单向增加关系,索引树的拓展都是在索引树一侧进行分裂创建。如果说有删除的空叶子节点,被新值利用的几率很低。这样,索引树就呈现出单向增加膨胀的趋势。如果同时该数据表有定期就数据归档这种需求,就可以适当考虑进行索引定期重构事宜。
ü 诊断分析索引树层次过高
索引树的构成、维护算法是复杂且带有一定随机特性的。作为树状结构的索引检索优势就在于平衡结构,从根节点开始,经过相同的比较和定位次数,都可以找到一个索引列取值的叶子节点。但是其中索引本身的层次level,也成为二元高度是索引健康程度的重要指标。一般的level高度不要超过三,如果我们分析一个关键索引的高度达到四或者是五层高度,那么就真的需要进行重构较好。
ü 其他一些特殊情景
除了上述两类,我们还要关注一些由于数据段对象本身原因引起的索引rebuild需要。比如,分区表的全局索引在分区被删除或者转移之后,对应行rowid变化,全局索引就需要rebuild,否则索引本身是失效unusable状态。另一个场景是进行数据段本身的move操作,转移表空间或者收缩高水位线HWM,对应的索引也会变为unusable状态,这样也需要对索引进行重建操作。
那么,我们如何确定需要管理的索引范围呢?
首先是确定DML频繁数据表索引范围,保持监控。数据表在系统中,活跃程度是不同的。读多写少型表的索引结构基本不需要管理(我们说通常的情况下),一次性的进行索引创建之后,发生变化的情况比较少,我们通常关注的力度稍稍弱些。对一些经常性发生DML操作的数据表,而且索引列是无规律变化的索引结构,我们最好在开发阶段就应该主动将其识别出来,作为一份重要的维护列表进行定期健康检查。
其次是先检测索引健康程度,之后确定是否重建。索引的rebuild一定要是有标准的。我们首先通过DML频繁程度和索引列形态,确定监控索引的优先级别顺序。之后,定期对关键操作索引进行监控,对监控出现问题的索引进行rebuild操作。采用监控的手段可以是analyze index XXX validate structure或者其他自定义工具。Rebuild备选依据可以是索引树高度超高或者死叶子节点比例过高。
最后一些结构维护操作要考虑对索引结构的影响。如果我们进行move或者分区操作,一定要将对索引的影响考虑在其中。如果忽视这部分操作,会给将来性能带来很大影响。
5、结论
索引的确是需要我们运维人员在系统运行过程中需要关注的一种重要内容。但是周期性的进行无差别索引重构的意义通常不是很大。笔者以为,还是要进行业务实际情况分析,明确一个经常性rebuild备选列表。之后进行索引列和实际情况分析,最后通过特定手段进行操作结构诊断,明确需要重构时,再进行重构操作较好。
来自 “ ITPUB博客 ” ,链接:http://blog.itpub.net/17203031/viewspace-703166/,如需转载,请注明出处,否则将追究法律责任。
转载于:http://blog.itpub.net/17203031/viewspace-703166/