Oracle优化案例 | 从执行计划定位SQL查询问题

Source

 

引入 | 记一次从执行计划定位SQL问题及性能优化的思考过程

一、问题复现:

写在前面的话,在端午假期之前,童鞋遇到了这样一个问题-SQL慢查询,在30万数据中查询,某个接口响应耗时约30s,页面直接挂掉,其中,SQL引入了视图,这里暂时就不贴代码了。

 

二、假设猜想:

1、在sql查询条件中,未对条件字段建立索引

2、在view中,表的访问方式连接顺序以及连接方式是否合理?

3、在已建立的索引中,索引是否命中,是否存在失效的情况,走全表扫描

 

三、思考过程:

从页面发起请求到后端服务接口响应耗时至页面直接挂掉:

1、首先,通过F12查阅页面加载耗时时间以及对后端接口加入耗时日志,得以分析最长耗时卡在DAO层,即SQL业务逻辑查询-结果响应。

2、接着,由于这里是远程现场排查,我们通过堡垒机的方式登入,然后打开Oracle客户端PL/SQL Developer,拷贝日志中打印的SQL语句在客户端查询。

3、然后,笔记本电脑的话可通过Fn+F5快捷键,在客户端打开当前SQL的查询计划进行具体排查,作进一步分析。

图一

图二

图三

这里,先对执行计划中一些概念作下详细说明

资源成本耗费 (COST)

全表扫描(TABLE ACCESS FULL)

索引扫描  (INDEX SCAN)

嵌套循环(NESTED LOOPS)

哈希连接(HASH JOIN)

排序-合并连接(SORT MERGE JOIN)

其中,每一个执行步骤都有对应的COST,可以从单步COST的高低,以及单步的估计结果集-对应ROWS/基数,来分析表的访问方式、连接顺序以及连接方式是否合理。

 

我们从执行计划中可知,其中有两张表走了全表扫描-TABLE ACCESS FULL,且扫描的行数ROWS以及COST也占居最高。分析到了这里,问题的根源离我们又近了一步。但是当我们查看打印出来的SQL语句并没有查到当前表名,那会不会是存在view视图中呢?

 

我们在PL/SQL客户端通过每个表的仔细查阅,终于在view视图中找到了走全表扫描的表,这下问题就可以随之迎刃而解​?

 

将复杂的SQL语句作查询步骤化解-"以大化小,以小化无",拆解成多个单步骤SQL片段,对每个SQL片段进行查询计划分析。但这里可优先对走全表扫描的表作进一步排查,分析之后,果然验证了之前的猜想。

 

上述全表扫描的表这里分别以A、B表昵称,在A、B表中分别有两个字段作为查询的条件属性,其中A表走模糊查询like '%A'而未命中索引,另一个B表是走条件查询未建立索引。针对上述排查后的结果,分别对A表作like 'A%',对B表查询条件字段建立INDEX索引,类型为Normal即可。

图四

Ok,now,我们继续看一下select的效果,页面正常请求后端服务接口,完成数据加载渲染,页面终于跑起来了,后端服务接口响应耗时日志打印,也从之前30s的请求耗时也缩短到了1-2s,继续在Oracle客户端查看执行计划,也未出现走全表扫描的情况。

 

四、解决方案:

针对失效的索引或查询条件字段未建立的索引,根据查询计划定位其问题及根源,并同时对参与条件查询的字段,调整并建立合适的索引及类型。

 

五、反思总结:

当然优化的点有很多,上述只是通过查询计划对索引作了合理的调整,当数据量基数非常之大的时候,关系型数据库可作分库分表非关系型数据库可对数据作建模设计,选取Elastic Search-分布式全文检索-倒排索引或MongoDb等等,根据合适的业务场景择优选取,具体也可参考小编CSDN博文

https://blog.csdn.net/yxd179

引出这样一个小问题-思考:当你去图书馆借书或者书店的时候,想必都有用到过通过书的类型,书的名称去缩小你需要查找的范围,那为什么通过目录,索引搜索就这么快?什么情况下索引会失效?Oracle、Mysql、ES索引底层又是怎么实现的呢?^_^

当然,我们也可以在工作之余去看看底层的数据结构,B树,B+树,Hash索引,倒排索引......

​附注:在高铁归途中,还是Mark一下之前的思考过程,坚持不易-自我驱动,由于时间等原因,阐述不一定俱全。本文暂时就到这里。对于SQL性能调优这块,方式有很多,希望对各位读者,在数据库SQL问题定位过程中能够有所帮助,欢迎提出宝贵建议^_^