美文网首页
把生产中的慢SQL从6000ms,一番折腾后运行只要40ms

把生产中的慢SQL从6000ms,一番折腾后运行只要40ms

作者: 小愚笨 | 来源:发表于2019-10-11 18:22 被阅读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 字段上也应该创建上索引

    相关文章

      网友评论

          本文标题:把生产中的慢SQL从6000ms,一番折腾后运行只要40ms

          本文链接:https://www.haomeiwen.com/subject/xgswoxtx.html