执行计划中判断索引是否生效,关键看type和key两列:type=all或key=null说明未用索引;key有值但rows远大于实际返回行数表示索引部分失效;extra出现using filesort或using temporary说明排序/分组未走索引。

先看执行计划,再动手改——不查 EXPLAIN 就调索引,90% 是白忙。
怎么看执行计划里索引到底走没走
核心就盯两列:type 和 key。
-
type=ALL:全表扫描,索引完全没用上 -
key=NULL:优化器压根没选任何索引 -
key有值但rows远大于实际返回行数:索引“擦边走了”,比如只用了联合索引前半段,后半段失效了 -
Extra出现Using filesort或Using temporary不代表索引失效,但说明ORDER BY或GROUP BY没走索引,可能需要覆盖索引补救
为什么 WHERE a > ? 有时走索引、有时不走
MySQL 优化器会估算扫描成本。当它判断「通过索引找到的行数超过全表 10%~30%」时,干脆放弃索引,直接全表扫描——因为回表开销太大,不如顺序读一次磁盘。
- 不是 bug,是成本权衡。比如
WHERE create_time > '2025-01-01'查出 80% 的数据,大概率type=ALL - 用
FORCE INDEX(idx_name)可临时验证是否真因误判跳过索引,但别长期硬写——这只是诊断手段,不是解法 - 真正解决要靠加过滤条件(如同时限定
status = 1)或拆分时间范围(如查最近 7 天而非全部未来时间)
联合索引为啥 WHERE b = ? 就不生效
联合索引 (a, b, c) 的 B+ 树是按 a → b → c 排序的,跳过 a 就找不到起点。
-
WHERE a = ? AND b > ? AND c = ?:c列索引失效(范围查询中断后续列) -
WHERE a = ? AND c = ?:c无法走索引,除非b是等值且出现在中间 -
WHERE b = ? OR c = ?:基本必然全表扫描,OR很容易让优化器放弃索引 - 高频查
b?别硬凑,要么单独建INDEX idx_b (b),要么重排为(b, a, c)——顺序不能拍脑袋定,得看查询模式
SELECT * 导致明明用了索引还是慢
这是最隐蔽的“伪走索引”:EXPLAIN 显示 key 有值、type=ref,但性能依然差——大概率是回表。
- 索引只存了
WHERE条件字段和主键,SELECT *还得根据主键去聚簇索引捞整行,IO 翻倍 - 解决办法是覆盖索引:把
SELECT中所有字段都塞进索引里,例如原语句SELECT id, name, email FROM users WHERE status = 1,就建INDEX idx_status_cover (status, id, name, email) - 建完再看
EXPLAIN,Extra出现Using index才算真正“纯索引扫描”
真正卡点往往不在“有没有索引”,而在“查询条件是否匹配索引结构”“返回字段是否触发回表”“优化器成本估算是否被数据分布带偏”。每次改之前,先 EXPLAIN 一眼,比瞎猜快十倍。











