索引是否被用上,关键看EXPLAIN中key非NULL且type不为ALL;type=ALL表示全表扫描,常见于隐式转换、函数操作或联合索引未满足最左前缀。

怎么看索引到底有没有被用上?
别信“我加了索引就一定走”,MySQL 优化器会自己选执行计划,索引建了≠用了。核心判断依据只有一个:EXPLAIN 输出里的 key 字段是否非 NULL,以及 type 是否为 ALL(全表扫描)。
常见误判点:
- 明明有索引,
EXPLAIN却显示type = ALL→ 很可能字段类型不匹配(比如INT列传字符串)、或对索引列用了函数(WHERE UPPER(name) = 'ABC') -
key显示索引名,但rows值极大 → 索引虽被选中,但实际过滤效果差,可能是选择性太低(如gender字段)或数据分布倾斜 -
Extra出现Using filesort或Using temporary→ORDER BY/GROUP BY没走索引排序,回表或临时表开销大
为什么组合索引有时只用前半截?
组合索引不是“全或无”,它遵循最左前缀原则,但中间遇到范围查询(>、<、BETWEEN、LIKE 'abc%')就会截断。例如索引是 (a, b, c):
-
WHERE a = 1 AND b > 10 AND c = 5→ 只能用到a和b,c不参与索引查找(key_len可验证) -
WHERE a = 1 AND c = 5→c完全失效,因为跳过了b -
WHERE b = 2 AND c = 3→ 整个索引不命中,type = ALL
注意:LIKE 'abc%' 是范围查询,LIKE '%abc' 则直接无法使用索引。
如何让索引命中率真正提升?
命中率不是靠“多建索引”堆出来的,而是让关键查询尽可能走索引 + 少回表。实操重点在三件事:
- 把高频
WHERE条件字段按查询频率和选择性排序,建组合索引;顺序原则:等值查询字段放前,范围查询字段放后,ORDER BY字段尽量包含在末尾 - 用覆盖索引减少回表:把
SELECT *改成只查需要的字段,并确保这些字段都在索引里(EXPLAIN中Extra = Using index) - 避免隐式类型转换:比如
user_id是INT,但查询写成WHERE user_id = '123',MySQL 会转成字符串比较,索引失效 - 监控真实负载下的索引使用情况:用
sys.schema_unused_indexes(MySQL 5.7+)查长期没被用过的索引,及时清理冗余索引
缓存命中率高 ≠ 索引命中率高,别混了
很多人把 Innodb_buffer_pool_read_requests 命中率当成“索引命中率”,这是错的。Buffer Pool 命中率反映的是“数据页是否在内存里”,和“SQL 是否走了索引”是两回事。
一个查询可以完全走索引(key 非空),但所有索引页都在 Buffer Pool 里 → 缓存命中率 100%,索引也命中了;
另一个查询没走索引(type = ALL),但表很小,整张表数据都在 Buffer Pool 里 → 缓存命中率还是高,但索引完全没用上。
真正要盯紧的,永远是 EXPLAIN 的输出,而不是某个全局状态变量。


















