把生产中的慢SQL从6000ms,一番折腾后运行只要40ms
2019-10-11 本文已影响0人
小愚笨
慢SQL报警
邮件接收到了慢SQL报警,一看时间吓一跳,竟然将近26s,看看是什么妖魔鬼怪?
由于涉及到生产,表名经过处理,并不是真实表名。。。
com.alibaba.druid.filter.stat.StatFilter | slow sql 25116 millis. SELECT count(1) FROM result oqr INNER JOIN o_query oq ON oq.sid = oqr.query_id WHERE 1 = 1 and oqr.status = 1 and oq.type not in (2,6) AND oqr.create_time >= ? AND oqr.create_time <= ?["2019-09-11 00:00:01","2019-10-11 23:59:59"]
开始分析
执行计划
初看就是两个表内连接,那看一看执行计划吧。。。
平台输出执行计划格式有问题,凑合看吧。
原始SQL执行计划
有一个全表扫描,而且行数很多啊,难怪很慢!
生产环境通过页面跳板的方式查询数据库,将这条SQL在页面执行的时候,第一次没有查出结果,因为平台有执行时间限制(20s),也意味着这条SQL超过20s还没有执行处理结果。
后来又执行了几次,通过执行记录来看,平均时间在6000ms左右。
两张表的索引情况
o_query表的索引情况 result表的索引情况通过执行计划的行数来看,result表应该是全表扫描了所有的记录。
猜测是不是两张表先筛选,再连接会更快呢
将SQL修改为如下
select count(1) from
(select query_id from result oqr where oqr.create_time between '2019-09-11 00:00:01' AND '2019-10-11 23:59:59' and oqr.status = 1) oqrs
inner join (select sid from o_query oq where oq.create_time between '2019-09-11 00:00:01' AND '2019-10-11 23:59:59' and oq.type not in (2, 6)) oqs where oqrs.query_id = oqs.sid;
查看执行计划吧
修改后的SQL执行计划通过执行计划来看,尽管还是全表扫描,但是行数却少了很多个量级啊!
通过在平台执行这个修改后的SQL,很快就执行完了,执行时间是40ms左右,这显然已经快很多很多了!!!
为什么修改后的SQL能快这么多呢?
猜测应该是跟两张表连接查询的执行过程有关系,本人英语渣渣,从官网找到执行顺序的资料很难啊,从网上搜索资料,发现有很多网友讲的没法解释。。
掘金小册子:MySQL 是怎样运行的:从根儿上理解 MySQL
MySQL是怎样运行的:从根儿上理解MySQL其中有一篇文章:两个表的亲密接触 —— 连接的原理
关于两表连接的执行过程,能恰好解释为什么修改后的SQL能快这么多了。。。
下图是从博文中截的图:
两表连接的执行过程
查看优化修改后的SQL
通过explain extended
查看优化修改后的SQL如下:
select count(1) AS `count(1)` from `o_query` `oq` join `result` `oqr` where ((`oqr`.`status` = 1) and (`oq`.`sid` = `oqr`.`query_id`) and (`oqr`.`create_time` between '2019-09-11 00:00:01' and '2019-10-11 23:59:59') and (`oq`.`create_time` between '2019-09-11 00:00:01' and '2019-10-11 23:59:59') and (`oq`.`type` not in (2,6)))
最后的一点思考
对于这条SQL应该还有优化的空间
o_query
表在 create_time
字段上也应该创建上索引