执行计划与慢查询
用途:把“这条 SQL 为什么慢”变成可验证的分析过程
采集慢查询
「采集慢查询」小节链接slow_query_log=ON,long_query_time建议 100-500ms(在线系统 1s 太宽),log_queries_not_using_indexes谨慎开(噪声大)。- 分析工具:
mysqldumpslow、Perconapt-query-digest、performance_schema/ sys schema。 - 关注总耗时占比而不是单条最慢:高频 50ms 的 SQL 往往比偶发 5s 的更影响整体。
EXPLAIN 关键列
「EXPLAIN 关键列」小节链接| 列 | 看什么 |
|---|---|
type |
system/const/eq_ref 最佳;ref/range 可接受;index 全索引扫描;ALL 全表扫描 |
key / key_len |
实际用到的索引与其前缀长度(判断联合索引用了几列) |
rows |
预估扫描行数(估算值,可能不准) |
filtered |
存储引擎返回的行中被 where 过滤后的百分比,低说明索引选择性差 |
Extra |
Using index(覆盖)、Using index condition(ICP)、Using filesort(额外排序)、Using temporary(临时表,需优化) |
EXPLAIN ANALYZE(8.0.18+)会真实执行并给出每步实际耗时与行数,是判断优化器估算偏差的首选手段。
常见慢因与对策
「常见慢因与对策」小节链接| 慢因 | 对策 |
|---|---|
| 索引缺失或选择性差 | 按查询重建复合索引,把等值列放前、区分度高的放前 |
| 函数/类型转换导致索引失效 | 改写为区间比较;必要时用函数索引或生成列 |
ORDER BY 触发 filesort |
让排序列进入索引尾部且方向一致;或先取 ID 再回表 |
深分页 LIMIT 1000000,20 |
游标式分页(WHERE id > last_id ORDER BY id LIMIT 20)或延迟关联 |
大 IN 列表 |
分批、或临时表 join |
| 统计信息陈旧导致选错索引 | ANALYZE TABLE;必要时 FORCE INDEX 并跟进根因 |
| 优化器成本模型不适合 | 检查直方图(ANALYZE TABLE ... UPDATE HISTOGRAM)、考虑改写 SQL |
| 锁等待(不是执行慢) | 看 data_lock_waits,属于并发问题不是索引问题 |
| 缓冲池不足、页读盘 | 看命中率与 innodb_buffer_pool_size |
优化流程(固定动作)
「优化流程(固定动作)」小节链接- 确认慢在哪一层:执行时间 vs 锁等待 vs 网络/结果集大小。
EXPLAIN+EXPLAIN ANALYZE对照估算与实际。- 改 SQL 或索引,小步验证(单条对比,不要一次改十处)。
- 压测或灰度观察 P95/P99,而不是只看平均。
- 上线后回到慢日志看板确认该模式消失。
结果集与网络
「结果集与网络」小节链接SELECT * 的问题不只是“多几列”:破坏覆盖索引、增大网络与序列化开销、放大缓冲池占用。列表页明确列字段;导出类查询走游标分批或专用只读实例。
常见误区
「常见误区」小节链接| 误区 | 修正 |
|---|---|
看 rows 小就认为快 |
锁等待、回表次数、排序都可能占大头 |
| 一律加索引 | 写放大与优化器选择成本;先看不走索引的原因 |
用 FORCE INDEX 当长期方案 |
数据分布变化后会劣化,需持续验证 |
| 只优化最慢的一条 | 高频中等耗时 SQL 才是主要 CPU 来源 |
生产直接跑大 EXPLAIN ANALYZE |
它会真实执行,重 SQL 要在从库或低峰做 |
延伸阅读
「延伸阅读」小节链接- MySQL 官方文档:EXPLAIN、Optimizer Cost Model、Slow Query Log
- Percona Toolkit 文档(pt-query-digest)
- 《高性能 MySQL》第 6-8 章