← 返回题目列表

MySQL 慢查询一般怎么排查和优化?

高频 简单 第 1 / 28 题 更新于 2026/07/27
MySQL慢查询SQL优化Explain

简化版

慢查询优化先定位慢 SQL,再看执行计划、索引、扫描行数、排序临时表、回表和锁等待,最后结合业务改 SQL、建索引或调整表结构。不要只看“有没有用索引”,低效索引、大量回表、深分页、锁等待都会让 SQL 变慢。

详细版

常见排查流程:

  1. 通过慢查询日志、监控、APM 或应用日志定位慢 SQL。
  2. EXPLAIN 看访问类型、索引选择、预估扫描行数和 Extra
  3. 必要时用 EXPLAIN ANALYZE 看实际执行耗时和实际行数。
  4. 检查 wherejoinorder bygroup by 是否匹配索引。
  5. 排查是否存在深分页、select *、隐式转换、函数包裹索引列。
  6. 看是否有锁等待、长事务、主从延迟、Buffer Pool 压力。
  7. 优化后用接近线上数据量验证,避免小数据样本误判。

优化手段通常包括:补联合索引、改写 SQL、减少返回列、拆分大事务、延迟关联、归档冷数据、分库分表或引入专门检索系统。

完整版教学

一、慢查询优化不能凭感觉开刀

一个接口慢,不一定是 SQL 慢;一个 SQL 慢,也不一定是缺索引。可能是锁等待、网络抖动、缓存失效、主从延迟,也可能是数据量增长后原来的索引不再适合。

所以第一步必须定位。慢查询日志能告诉你哪些 SQL 超过阈值,APM 能把慢 SQL 和具体接口关联起来,数据库监控能看到 CPU、I/O、锁等待、连接数等整体状态。

例如接口耗时 2 秒,SQL 本身可能只执行 80ms,剩下时间耗在远程服务、序列化或网络;也可能 SQL 执行计划很好,但等锁等了 1900ms。慢查询优化的第一步是把“慢在哪里”拆开,而不是看到数据库就先加索引。定位证据通常来自慢日志、APM trace、数据库监控和应用日志的时间线对齐。

接口慢 -> 查 trace
      -> SQL 慢:看慢日志/执行计划
      -> SQL 不慢:看网络、缓存、远程调用、应用逻辑
      -> SQL 等待久:看锁、连接池、I/O

二、Explain 是入口,不是终点

EXPLAIN 告诉你优化器准备怎么执行 SQL。重点看:

  • type:访问方式是不是全表扫描或大范围扫描;
  • key:实际选择的索引是否符合预期;
  • rows:预计扫描行数是否过大;
  • filtered:过滤后剩余比例;
  • Extra:是否出现额外排序、临时表、覆盖索引、索引下推。

EXPLAIN 依赖统计信息,是估算。MySQL 8 支持 EXPLAIN ANALYZE,可以看到实际执行路径、耗时和行数。排查复杂慢 SQL 时,它比只看估算更接近真相。

看 Explain 要围绕成本主线:有没有走合适索引,预计扫描多少行,是否需要额外排序或临时表,是否大量回表。比如 type=range 不一定好,如果 rows=5000000key 有值也不一定好,如果低选择性索引导致大量回表。慢查询优化最怕只看单个字段下结论。

字段关注点常见风险
type访问方式ALL、大范围 range
key实际索引没选预期索引
rows估算扫描量扫描量过大
filtered过滤比例大量无效候选
Extra额外操作filesort、temporary、大量 where 过滤

记忆钩子:Explain 是地图,不是测速仪;地图能告诉你可能绕路,真实耗时还要用日志和执行数据确认。

三、索引优化要围绕访问路径

加索引不是给每个字段都建索引,而是服务高频查询路径。比如:

select id, title
from article
where author_id = ?
  and status = ?
order by publish_time desc
limit 20;

更合理的思路是建立 (author_id, status, publish_time),让过滤和排序同时受益。如果返回列很少,还可以评估覆盖索引,减少回表。

如果这个查询每天执行 100 万次,优化收益非常明显;如果它只是管理员偶尔查一次,就不一定值得为它增加宽索引。索引优化要看频率、耗时、数据量和写入代价。一个好索引应该让 SQL 少扫描、少排序、少回表,而不是只是让 Explain 的 key 不为 NULL。

四、很多慢 SQL 是“扫描太多”

常见扫描放大器有:

  • 深分页:limit 1000000, 20 需要先走过大量记录;
  • 低选择性索引:比如性别字段,走索引也可能要回表很多行;
  • 范围太大:时间条件跨度过长;
  • select *:返回列过多,增加回表和网络传输;
  • 前置模糊:like '%abc' 无法用普通 B+ 树快速定位。

优化的核心目标往往不是“让 SQL 看起来用了索引”,而是让它少扫描、少回表、少排序、少等待。

可以用一个粗略对比:当前页只需要 20 条,但深分页扫描 1000020 条;某条件命中 80% 数据,二级索引回表 80 万次;select * 读取很多不展示的大字段,网络传输和回表页访问都增加。这些都是“返回少、处理多”的典型慢查询。

慢 SQL 常见成本:
扫描行数大
回表次数多
排序/临时表重
锁等待久
返回列过宽

五、锁等待也会表现成慢查询

如果 SQL 执行计划正常但耗时很长,要怀疑锁。比如一个长事务更新了某批数据但迟迟不提交,其他事务更新同一批记录时就会等待。

这类问题靠加索引未必能解决,还要看事务边界、访问顺序、热点行、死锁日志和应用调用链。优化方式可能是缩短事务、调整更新顺序、拆分批量任务或做幂等重试。

比如 update orders set status='PAID' where id=1001 通过主键命中,执行计划没有问题,但它等待另一个事务释放同一行锁,慢日志里仍可能记录很长耗时。此时加索引没有意义,应查长事务、锁等待、事务内是否有远程调用,以及热点行更新是否过于集中。

六、优化后必须复测和防回退

慢查询优化不是改完 SQL 或索引就结束。要在接近线上数据量下验证 Explain、真实耗时、CPU、I/O、锁等待和业务结果是否正确。上线后还要观察慢日志和核心接口指标,避免新索引拖慢写入,或 SQL 改写改变结果语义。

闭环:
定位 -> 分析 -> 修改 -> 复测 -> 灰度 -> 观察 -> 记录经验

尤其要注意测试数据量。开发库 1 万行时,任何写法都可能很快;线上 1 亿行时,索引顺序、回表和排序成本才真正暴露。

七、常见误区与追问

  • 误区:慢查询优化就是加索引。 缺索引常见,但锁等待、深分页、大量回表、排序临时表、返回列过宽和缓存冲刷也会导致慢。
  • 误区:Explain 里用了索引就不用优化。 低选择性索引、大范围扫描和大量回表仍可能很慢。
  • 误区:只在小数据开发库验证优化效果。 小数据无法暴露扫描、排序和缓存成本,必须用接近线上规模的数据验证。
  • 误区:优化 SQL 可以不关注业务语义。 条件移动、JOIN 改写、分页方式变化都可能改变结果,性能优化必须保持语义正确。
  • 追问:执行计划正常但 SQL 很慢怎么办? 查锁等待、长事务、I/O 压力、Buffer Pool 命中率、连接池等待和主从延迟。
  • 追问:慢查询优化的闭环是什么? 定位慢 SQL,分析执行计划和真实耗时,针对扫描/索引/排序/锁等待优化,复测后灰度上线并持续观察。

八、加强记忆

慢查询排查要按证据走:先定位慢 SQL 和慢发生在哪个阶段,再用 Explain 看访问路径,用真实执行数据验证估算,最后围绕索引、扫描行数、回表、排序临时表、锁等待和返回列做优化。改完必须用接近线上数据量复测,并观察上线后的读写指标。不要把慢查询优化简化成“加索引”,真正要减少的是无效扫描、无意义等待和不必要的数据处理。