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多看两眼,比盲目建索引有用得多。
