某客户近期因统计信息问题执行了一条错误的SQL语句,导致CPU资源耗尽,系统出现严重故障。不得不下线部分功能,暂时解决问题。后来开发者尝试通过SQLPROFILE解决了计划执行错误的问题,并恢复了系统。事后,远程健康服务中心和Oracle原厂参与了故障汇总,均认为是统计信息不准确导致执行计划错误。当时我也提出了一个比较彻底的方案,就是把USERID和date这两个索引合并成一个复合索引。但是因为表太大,开发者不愿意重建索引,所以没有实现。这个问题一般出现在月底和月初,只要有硬分析就很容易出问题。自从加入了SQLPROFILE之后,就停了一段时间。但是昨天又出现了一个问题。早上起来,CPU突然飙升到100%。因为类似的问题,我很快怀疑这个SQL。做一个AWRSQRPT发现确实有两个执行计划,SQL使用了错误的索引。SQLPROFILE似乎没有作用。当故障报到远程健康服务中心后,我们的支持人员建议他们使用SQLPLANBASELINE固化执行计划,系统很快就恢复了。虽然问题很快得到解决,但用户还是有一些疑虑。为什么上次出现问题时,研发部采用的通过SQLPROFILE优化执行计划的策略失败了。实际上,用户将SQLPROFILE视为绑定执行计划。SQLPROFILE原则上不是强制绑定执行计划,而是通过SPM分析,发现统计信息与实际运行情况不符,所以设置了SQLPROFILE。一些TABLE_STATS提示,以便优化器可以使用更准确的生成执行计划。下图来自Oracle的官方文档,可以很好的解释SQLPROFILE的机制。在SQLPROFILE提供的HINT中,并没有指定执行计划的内容,只是设置了一些统计信息的修正提示。因此,如果设置了SQLPROFILE的SQL语句,那么在解析SQL时,会根据PROFILE中对象的统计信息来修正执行计划。这样做的好处是灵活,比如修改某个表上的索引。解析这条SQL时会考虑这些因素,选择更好的执行计划。但是,也有缺点,就是有时候,执行计划还是会出错。SQLPROFILE是Oracle10g引入的新功能。从11g开始,Oracle也看到了SQLPROFILE的不足,于是引入了一个新的功能,SQLPLANBASELINE。SQLPLANBASELINE的作用与SQLPROFILE类似,但采用的方法完全不同。根据ORACLE官方文档,SQLPLANBASELINE用于避免有问题的执行计划。SQLPLANBASELINE采用强制绑定执行计划的方式。上图也是来自Oracle的官方文档。这张照片非常清晰。从上面我们可以看出,SQLPROFILE是用来纠正过去错误的执行计划,但不限制以后不再使用这个错误。实施计划。SQLPLANBASELINE用于保证以后不会使用错误的执行计划。SQLPLANBASELINE是一组可接受的计划。每个计划都是使用一组指定特定计划的大纲提示来实施的。不同的是SQLPROFILE也是使用hints来实现的,但是这些hints并不指定任何具体的计划,而只是更正优化器在估算成本时产生的错误统计信息。因为SQLPROFILE没有将优化器绑定到任何一个计划,所以SQLPROFILE比SQLPLANBASELINE更灵活。初始化参数和优化器统计信息的更改使优化器能够选择更好的计划。而一旦设置了SQLPLANBASELINE,那么这条SQL以后就只能使用固定的执行计划了。当某个SQL根据不同的绑定变量有多个不同的最优执行计划时,SQLPROFILE可以充分发挥其灵活性。但是SQLPROFILE会有一定的出错可能性。SQLPLANBASELINE就简单粗暴了很多,强制指定执行计划。这在某个SQL只有一个最优执行计划时最有效。但是,它的缺点是缺乏灵活性。对于SQLPROFILE和SQLPLANBASELINE,如果选错了,很容易造成不可预知的隐患,需要非常慎重选择。Oracle建议通过SPM的建议来选择,而不是依赖DBA自己的判断,避免误用。但是,我认为类似的问题往往与索引设计的混乱有关。优化索引设计可以从上游解决此类问题。
