一条查询突然变慢了,你怎么排查?
先说结论
慢查询排查四步走:
① 开启慢查询日志,找到慢SQL —— 先知道“谁慢了”
② 用EXPLAIN分析执行计划 —— 看“为什么慢”
③ 根据分析结果优化 —— 加索引、改SQL、调配置
④ 验证优化效果 —— 确认“真的快了”
先把这段讲顺;面试官追问时,再展开下面的原理和细节。
详细讲解
慢查询排查是MySQL面试的“开局王炸”,几乎每场必问。但很多人的回答停留在“看EXPLAIN”这一步就卡住了——EXPLAIN看什么、怎么看、看完怎么优化,说不清楚。今天用一个真实的生产场景,把慢查询排查的完整流程走一遍。
业务场景:订单查询突然变慢
我在元宇宙社交App那家公司,有个订单查询接口,原本响应时间20ms,突然变成了3秒。服务端开始报超时告警。
-- 问题SQL
SELECT o.order_id, o.amount, u.nickname
FROM orders o
JOIN users u ON o.user_id = u.id
WHERE o.status = 'paid'
AND o.created_at > '2025-01-01'
ORDER BY o.created_at DESC
LIMIT 20;
第一步:找到慢SQL
-- 开启慢查询日志
SET GLOBAL slow_query_log = ON;
SET GLOBAL long_query_time = 1; -- 超过1秒记录
-- 查看慢查询日志位置
SHOW VARIABLES LIKE 'slow_query_log_file';
生产环境我们一般用监控工具(如Percona PMM或阿里云RDS的慢SQL分析)直接查看,不用手动开日志。
第二步:EXPLAIN分析执行计划
EXPLAIN SELECT o.order_id, o.amount, u.nickname
FROM orders o
JOIN users u ON o.user_id = u.id
WHERE o.status = 'paid'
AND o.created_at > '2025-01-01'
ORDER BY o.created_at DESC
LIMIT 20;
EXPLAIN结果里最关键的几个字段:
| 字段 | 含义 | 你应该看什么 |
|---|---|---|
| type | 访问类型 | ALL=全表扫描(危险),ref/range=用到索引(正常) |
| key | 实际使用的索引 | NULL=没用索引(危险) |
| rows | 预估扫描行数 | 越小越好 |
| Extra | 额外信息 | Using filesort/Using temporary=可能有问题 |
我看到的结果是:orders表的type是ALL,key是NULL,rows显示500万。意思是全表扫描了500万行,难怪慢。
第三步:定位原因并优化
问题很清楚:status和created_at上没有合适的索引。解决方案:加一个组合索引。
-- 加组合索引(核心优化)
ALTER TABLE orders ADD INDEX idx_status_created (status, created_at);
-- 再次EXPLAIN,type变成range,rows变成2000,查询时间从3秒→ 15ms
为什么是(status, created_at)而不是单独的索引?因为WHERE里同时用到了这两个字段,组合索引可以一次性过滤,效率更高。而且status放前面是因为它是等值条件(=),created_at是范围条件(>),等值条件在前才能充分利用索引。
面试高频追问:常见的索引失效场景
这才是面试官真正想听的。我总结了生产环境最常见的5种索引失效场景:
① 对索引列做函数/运算:
-- ✖ 索引失效:对created_at做了函数转换
WHERE DATE(created_at) = '2025-03-15'
-- ✔ 索引生效:用范围查询
WHERE created_at >= '2025-03-15' AND created_at < '2025-03-16'
② 隐式类型转换: 字段是varchar但查询用了数字,MySQL会自动转换,索引失效。
-- ✖ phone是varchar,但用了数字查询,触发隐式转换
WHERE phone = 13800138000
-- ✔ 加引号,避免隐式转换
WHERE phone = '13800138000'
③ 最左前缀原则违反: 组合索引(a,b,c),查询只用了b和c,跳过了a,索引失效。
④ LIKE以%开头: LIKE '%keyword'无法使用索引,LIKE 'keyword%'可以。
⑤ OR条件: 如果OR的两侧不是都有索引,MySQL可能放弃索引走全表扫描。
实战踩坑:索引加了但没用上
我在元宇宙社交App还遇到过一个更难发现的问题:明明加了索引,EXPLAIN也显示用了索引,但查询还是慢。原因是返回的数据量太大——索引过滤后仍有50万行,还要回sort。解决方案是加了更精确的过滤条件(缩小时间范围),并用覆盖索引避免回表。
-- 覆盖索引:索引包含了查询需要的所有字段,不需要回表
ALTER TABLE orders ADD INDEX idx_cover (status, created_at, order_id, amount);
-- EXPLAIN显示Using index,说明不需要回表了
总结
慢查询排查四步走:找到慢SQL→EXPLAIN分析→加索引/改SQL→验证效果。EXPLAIN重点看type、key、rows、Extra。熟记5种索引失效场景。面试时用一个真实的排查案例串起来说,比干巴巴列规则有说服力得多。
下一篇聊一个很具体的场景题:一张订单表5000万行,查询越来越慢,你怎么办?分库分表、归档、还是其他方案?
你们排查慢查询的流程是什么?评论区聊聊~
关注「Wood聊大数据」| 9年大数据老兵,聊技术、聊职场、聊成长