内行透底:EXPLAIN 拆解,慢查询秒变 50ms 的硬招
|
去年九月某周三下午三点,服务器监控的告警弹窗蹦出来时我刚给产品改完第三个版本的交互原型,手指还沾着数位板的油墨——不是油,是上次吃外卖蹭的芝麻糊,没擦干净。运维的小姑娘隔着工位喊我,说用户后台的订单统计页面突然卡死,点一次等半分钟,用户都在客服群里炸了。 我原以为是缓存炸了,结果登上服务器后台,一看慢查询日志,单条统计语句的执行时间快到六秒,再看EXPLAIN输出,type列显示的是ALL,全表扫描。这不是第一次碰到这种情况,哪年年初我在同个项目组处理过一次类似的全表扫描,当时花了三天才揪出索引漏加的问题。 接手这个订单统计的是个刚转后台的小伙子,叫小周,我上次路过他工位时他还在啃外卖,代码注释写得稀碎,还把统计条件的and写在group by外面。我盯着EXPLAIN的Extra列看,Using filesort和Using temporary并排挂着,跟他的代码对应上了——他把统计时的时间筛选放在子查询里,外层再group by日期,索引根本没用到。 我蹲在小周工位旁边,把他的代码拖出来,指着EXPLAIN的输出跟他说,不是索引加了就完事儿,你得看EXPLAIN里的type和rows,这慢查询的根源就在这俩地方。小周挠头,说他之前看别人加索引就完事,没注意过EXPLAIN的详细内容,这次是项目赶进度没来得及查。 我把那条SQL改了两个地方,把时间筛选移到子查询的where条件里,再给订单表的create_time和user_id加联合索引,改完执行了一次,时间直接降到了五十毫秒以内。我跟小周说,内行拆慢查询,不是凭感觉加索引,是盯着EXPLAIN的每一行输出抠,type得是range或者ref,rows得是预估行数的十分之一以内,Extra里不能有Using filesort和Using temporary。 小周后来跟着我查了一下午的慢查询,我们又找出了两个有类似问题的语句,都是因为索引没用到导致的全表扫描,改完之后整个后台的响应时间都降下来了。那天晚上我走的时候,运维小姑娘给我递了瓶冰可乐,说她监控里再也没弹过同样的告警。 哪年年底我处理过一次电商后台的慢查询,当时的情况比这次更复杂,那条SQL涉及三张表的关联,我花了两天时间用EXPLAIN拆解,最后调整了关联顺序和索引,把执行时间从十秒降到了两百毫秒。这次跟上次比,我更有经验了,知道怎么快速定位问题,不用再像上次那样挨个试索引。 有个老同事之前跟我聊过,说他觉得EXPLAIN拆解太麻烦,不如直接用第三方工具,比如可视化的分析平台。我当时就反驳他,第三方工具本质上也是对EXPLAIN的封装,你连底层逻辑都没搞懂,工具给你报个type是ALL,你都不知道这是啥意思,更别说判断是不是真的有问题。 我原以为EXPLAIN拆解是个很简单的活儿,只要看几列输出就能搞定,结果这次碰到的情况让我明白,不是这么回事。那条改完的SQL,EXPLAIN里的type是range,rows只有一百多行,Extra里只有Using index,这才是正常的状态,之前的全表扫描是因为把筛选条件放错了位置,导致索引失效。 我跟小周说,做后台开发,慢查询是个躲不开的问题,你得学会用EXPLAIN拆解,这是最基础的技能,也是最有效的硬招。我从业十九年,见过太多因为忽略EXPLAIN导致的性能问题,小到页面加载慢,大到服务器宕机,都是因为这一点点的细节没注意到。 哪年年初我在公司的技术分享会上讲过EXPLAIN拆解的内容,当时台下坐了两百多个开发,提问的人很多,有个刚入职的小伙子问我,有没有更快捷的方法。我当时跟他说,没有,慢查询的拆解就得靠EXPLAIN,得一行一行看输出,得抠每一个字段的含义,没有捷径可走。 这次的订单统计问题,让我又一次意识到,内行和外行的区别,就在于有没有耐心去拆解EXPLAIN的每一行,有没有能力去判断输出的每一个字段的含义。很多人觉得加索引就能解决问题,但实际上,索引用错了还不如不用,这就是优胜劣汰的地方,能沉下心拆解EXPLAIN的人,才能写出高效的SQL,才能避免慢查询的问题。 我跟小周说,这次的事情给他提个醒,以后写SQL,一定要记得用EXPLAIN看一下执行计划,不要等出了问题再补救。小周点点头,说他以后每次写SQL都会先跑一遍EXPLAIN,确保没有问题再提交。 我从业十九年,见过太多因为忽略细节导致的性能问题,慢查询拆解看似简单,实则考验的是开发的耐心和基本功。很多人追求快速出活,却忽略了性能优化的重要性,最后导致项目上线后出问题,反而要花更多的时间去补救。 那天晚上我回家后,翻了翻之前的技术笔记,里面记录了很多EXPLAIN拆解的案例,这次的订单统计问题,被我加在了笔记的最前面,标注了重点。我想,以后再碰到类似的问题,我可以更快地定位和解决。 我原以为这次的问题解决后就没事了,结果后来小周跟我说,他又碰到了一条慢查询,还是因为索引没用到,我过去一看,还是把筛选条件放错了位置,跟这次的问题一模一样。我跟他说,要举一反三,不能犯同样的错误,EXPLAIN的拆解逻辑都是相通的,只要掌握了方法,就能快速解决问题。 哪年年底我处理过一次社交平台的消息查询慢问题,那条SQL涉及用户的好友关系和消息记录,我用EXPLAIN拆解后,发现关联顺序不对,导致全表扫描,调整关联顺序后,执行时间从八秒降到了一百五十毫秒。那次的问题让我明白,EXPLAIN拆解不仅要看索引,还要看关联顺序和筛选条件的位置,这些都是影响性能的关键因素。 我跟小周说,慢查询的拆解,核心就是读懂EXPLAIN的输出,type要优,rows要少,Extra要干净,只要满足这几个条件,SQL的性能就不会差。很多人只看执行时间,不看执行计划,这是本末倒置的做法,只有先搞懂执行计划,才能真正解决慢查询的问题。
文章配图,仅供参考 上次跟老同事聊起EXPLAIN,他还在说第三方工具好用,我现在依然坚持我的观点,工具可以用,但不能依赖工具,你得自己懂底层逻辑,不然工具给你报个问题,你都不知道怎么解决。EXPLAIN是MySQL自带的工具,是最基础也是最有效的,它能给你最真实的执行计划,让你看到SQL的每一步执行过程。 去年九月的那次经历,让我对EXPLAIN的拆解有了更深刻的理解,这就是我今天要讲的硬招,没有花里胡哨的技巧,就是一行一行看EXPLAIN的输出,抠每一个细节,找到问题的根源,然后针对性地解决。这就是内行的硬招,也是优胜劣汰的关键,能沉下心做这件事的人,才能写出高效的SQL,才能避免慢查询的问题。 (编辑:站长网) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |


内行透底:索引失效致10s慢查询,优化后2ms搞定
