前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >一个执行计划异常变更的案例 - 前传

一个执行计划异常变更的案例 - 前传

作者头像
bisal
发布2019-01-29 15:29:52
5120
发布2019-01-29 15:29:52
举报

今天快下班的时候,几位兄弟来聊一个问题,大致是昨天应用使用的数据库突然出现性能问题,DBA发现有一些delete语句执行时间骤长,消耗大量系统资源,导致应用响应时间变长积Q。目前掌握的信息如下: (1) 应用已经很久未做过更新上线了。 (2) 据开发人员反馈,从之前的应用日志看,未出现处理时间逐步变长的现象。 (3) 这是一套RAC+DG的环境,版本未知,猜测至少应该是11g的版本。 (4) 这次突然出现大量执行时间超长的SQL语句,是一系列delete语句,例如delete from table where key=:1or key=:2 … key=:13这种SQL,应用正常的处理逻辑中都会使用这条语句,因此并发较高,使用了绑定变量,key字段不是主键,但有索引。目前尚不知晓字段是否存在直方图。 (5) 表的数据量大约5000万,初步反馈得知key=0的记录大约1500万,执行时间超长的SQL语句都使用了key=0的条件,至于key=0的真实数据量,以及出现问题的SQL语句使用的绑定变量具体值,这些还需要开发再次确认。 (6) DBA反馈SQL语句执行计划发生了变化,从数据库层面做了一些操作后,问题解决,目前尚不知晓做了什么具体的操作。

之所以这篇文章标题是“前传“,是因为现在已知的上述信息很有限,不能给出非常明确的出错原因,需要明日进一步和开发以及DBA了解后才能做深入的分析,了解真正的问题根源。

这里想说的什么情况下可能造成SQL执行计划发生改变?有很多种情况,这里抛砖引玉举一个例子。再次声明,以下实验和上面的问题可能没有直接关系,仅是引申的一些观点,上面问题的根源还有待进一步确认和排查。

实验: 创建测试表t1,其中name字段设置索引,取值为10000个A和1个B。

这里写图片描述
这里写图片描述

我们看下用查询条件name=’A’的SQL使用了什么执行计划,

这里写图片描述
这里写图片描述

再看下使用查询条件name=’B’的SQL用了什么执行计划,

这里写图片描述
这里写图片描述
这里写图片描述
这里写图片描述

显而易见,因为取值为A的记录占据了10000/10001接近100%的比重,即这查询条件返回了几乎表的所有数据,使用全表扫描的成本一般会小于使用索引的成本,由于TABLE ACCESS FULL会扫描表高水位线以下的数据块,且为多块读,即一次IO会读取多个数据块,具体数据块数量取决于参数db_file_multiblock_read_count,而INDEX RANGE SCAN则是单块读,同时若select字段不是索引字段的话,还需要回表,累积起来,IO次数就会可能很大,因此相比起来,全表扫描的IO可能会远小于索引扫描。

取值为B的记录占据了1/10001很小的比重,因此使用索引扫描,直接访问B*Tree二叉树,定位到这一条数据的rowid再回表查询所有select字段的成本要远小于扫描整张表数据的成本。

为了证明,可以查看这两条SQL对应的10053事件,如下是name=’A’的trace,可以看出全表扫描的成本值是49.63,索引扫描的成本值是351.26,全表扫描的成本更低一些。

这里写图片描述
这里写图片描述

如下是name=’B’的trace,可以看出全表扫描的成本值是49.40,索引扫描的成本值是2.00,索引扫描的成本值更低一些。

这里写图片描述
这里写图片描述

这个场景可以看出,Oracle的CBO模式会根据字段的取值比重调整对应的执行计划,无论如何,都会选择成本值最低的一个执行计划,这也是CBO优于以前RBO的地方,这里仅用于实验,因为一般OLTP的应用会使用绑定变量的写法,不会像上面这种使用常量值的写法,11g之前,可能带来的一些负面影响就是绑定变量窥探的作用,即对于使用绑定变量窥探的SQL语句,Oracle会根据第一次执行使用的绑定变量值来用于以后的执行,即第一次做硬解析的时候,窥探了变量值,之后的软解析,不再窥视,换句话说,如果上面实验的SQL语句使用了绑定变量,第一次执行时name=’A’,则接下来即使使用name=’B’的SQL语句仍会使用全表扫描,不会选择索引扫描,vice versa。相关的实验dbsnake的书中会有很详细的说明,可以参考。11g之后,有了ACS自适应游标的新特性,会根据绑定变量值的情况可以重新生成执行计划,因此这种问题得到了缓解,当然这些都是有代价的,缓解了绑定变量窥探的副作用,相应地可能会导致有很多子游标,具体的算法可以参考dbsanke的书,这儿我就不班门弄斧了。11g默认绑定变量窥探是开启的,由以下隐藏参数控制,

这里写图片描述
这里写图片描述

综上所述,针对这场景,如果值的选择性显著影响执行计划,则绑定变量的使用并不可靠,此时选择字面值的方式可能会更合适一些,如果值的选择性几乎相同,执行计划不会显著改变,此时使用绑定变量是最优的选择,当然前提是OLTP系统。

对于多次执行SQL语句,执行计划发生变化的情况可能还有很多,例如11g的新特性Cardinality Feedback带来的一些bug,包含直方图的字段作为查询条件但统计信息不准(dbsnake的书中有一个案例)等,有机会做一些实验,再呈现出来。

至于本文开始提到的这个问题,进一步了解相关信息后,可以详细地介绍下。

本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
原始发表:2016年12月20日,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档