
经过分析发现,表上原有索引XXXX_IDX2(账号,日期) ,为了新业务应用,新建了第三个索引 XXXX_IDX3(日期,时间戳)(原计划创建一个时间戳的索引,后来在测试中发现加上日期后应用效果更好,于是对原计划做了微调,实际上在很多实施中,微调往往也是引起问题的重要因素)。检查了DBA_PART_COL_HISTOGRAMS中的和索引相关的字段的统计数据:
列名 | LOW VALUE | HIGH VALUE | 独立值数量 | 说明 |
账号 | 00000000019011 | 9981000000000046719001 | 11778048 | 和201903分区相同 |
日期 | 20200701 | 20201001 | 91 | |
时间戳 | 1554048002404647 | 1561900323544575 | 126771200 | 和201903分区相同 |
经分
出现问题的SQL是首先从另外一张表中获得数据,然后根据“账号”和这张表关联,同时在这张表中以“日期”为条件进行数据过滤。在ORDER BY里面有账号,日期和时间戳。按一般情况分析,同时具有账号和日期的XXXX_IDX2是更优的选择,为什么ORACLE CBO会选择错误的索引呢?在生产环境的SNAPSHOT测试环境中,我们对此进行了模拟,并通过EVENT 10053跟踪CBO的决策算法。通过10053 TRACE,我们发现一个问题:

其中的IDX4是模拟实际生产环境的IDX3创建的索引。CBO计算该索引成本远低于其他索引,其COST是其他索引的85万分之一。这是十分不正常的。在TRACE里查找索引的相关属性:

原来这个索引没有分析,对于表上有统计数据,索引没有分析的情况,CBO会使用缺省值,LB为25来评估成本。和其他索引LB为60多万相比,无论如何,这个索引的成本都是最低的。因此只要其他索引和这个索引有共有字段,那么在CBO评估中,就肯定会落下风。这也是大量SQL采用了错误执行计划的原因。为什么这个索引会没有分析呢?按理说新建索引都会自动进行统计的。经过讨论发现,原来这张表的统计信息被锁定了。由于这是一张季度分区表,因此有些SQL可能会在季度初的第一天执行计划存在问题,于是在去年就锁定了统计信息。因此新建索引就没有分析了。
在测试环境中解除表的统计分析限定,然后对该索引进行了分析。分析后有问题的执行计划均恢复正常。从10053 trace中也可以看到,索引的状态也正确了:


实际上这个案例十分典型,也可以总结出相当多的经验。对于锁定统计信息,分区表在第一天的一些SQL的执行计划异常问题等,都是十分值得深入讨论的。今天我们的讨论主题是百密难免一疏忽,所以这些题外话我们找时间再聊。最后我们总结一下在百密中如何避免这一疏。
对于这种核心类的交易系统,是十分敏感的,因此哪怕是增加一个索引都需要做严格的评估,否则出现的后果可能是企业无法承受的。这个项目的前期工作做的很好,在大家看来是十分小的一件事都广泛征求了各方面专家的建议。不过在后面的一些小的变更上,比如增加日期字段,并没有再重新做评估。这也是我们最容易疏忽的,每个变更都被认为是小变更,无关大局,实际上这种疏忽十分致命。另外在分析的全面性方面,也缺乏经验,通过这个案例,对于表上添加索引,应该增加查询该表统计数据是否锁定的检查。同时,建完索引后应该立即检查索引的统计数据是否正常,否则很容易出问题。这次是因为客户的监控比较完善,不用检查索引统计信息是否正常,业务就已经报警了。




