MySQL查询慢不能只靠加索引,关键要读懂EXPLAIN的type、key、rows、Extra字段:type为ALL表示全表扫描,key为NULL未必真失效,rows是预估扫描行数,Extra出现Using filesort或temporary是性能红灯。

MySQL 查询慢,不是加索引就能解决的;真正卡住你的,往往是 EXPLAIN 看不懂、执行计划里 type 是 ALL 却没意识到全表扫描、或者 key 显示 NULL 却以为索引“失效”了。
怎么看懂 EXPLAIN 输出里的关键字段
EXPLAIN 不是只看有没有用上索引,重点在 type、key、rows、Extra 四个字段:
-
type从好到差:const≈eq_ref>ref>range>index>ALL。出现ALL基本等于没走有效索引,哪怕key列显示有值 -
key是实际被选用的索引名;NULL表示没走索引,但也要结合possible_keys看——如果后者非空而前者为NULL,说明优化器认为走索引反而更慢 -
rows是预估扫描行数,不是结果行数;它远大于实际返回行(比如SELECT COUNT(*)返回 1 行,rows=100000)就值得警惕 -
Extra里出现Using filesort或Using temporary是性能红灯,尤其二者同时出现,基本意味着排序+分组逻辑无法利用索引完成
为什么 ORDER BY 加了索引还是 Using filesort
索引能避免排序,前提是查询条件和排序字段共同满足「最左前缀 + 顺序一致」。常见失效场景:
- WHERE 用了范围查询(
>、BETWEEN、LIKE 'abc%'),后面跟的ORDER BY字段无法复用索引排序能力 - WHERE 和 ORDER BY 涉及不同字段组合,比如索引是
(a,b,c),但查询是WHERE a = 1 ORDER BY c——c不在最左连续位置 - ORDER BY 中混用 ASC/DESC,如
ORDER BY b ASC, c DESC,而索引定义是(b,c)(MySQL 8.0 以前不支持混合方向索引) - SELECT 中包含非索引覆盖字段,导致回表后无法保持有序,必须二次排序
FORCE INDEX 什么时候该用、什么时候别硬上
优化器选错索引时,FORCE INDEX 是临时止血手段,但不是银弹:
- 适用场景:
EXPLAIN明确显示选了低效索引(比如走了小基数字段索引而非时间范围索引),且你确认业务数据分布稳定、该索引确实更优 - 风险点:MySQL 版本升级、统计信息更新、数据量突增都可能导致强制索引反而更慢;线上高频 SQL 强制索引后需持续监控
slow_log中的Rows_examined - 比
FORCE INDEX更稳妥的做法是先用ANALYZE TABLE更新统计信息,再观察是否自动修正;或通过OPTIMIZER_TRACE查看优化器弃用某索引的真实原因(比如成本估算偏差)
真正难的不是查出哪一行慢,而是理解优化器为何放弃你认为“显然更好”的索引——它看到的数据分布、成本模型、甚至临时内存限制,都可能和你直觉不同。盯着 rows 和 Extra 多看两眼,比盲目建索引有用得多。











