EXPLAIN显示type=ALL却没走索引,主因是隐式类型转换或对索引列使用函数导致索引失效,而非索引未建;需检查字段类型、避免函数操作、确认统计信息准确及联合索引顺序匹配查询模式。

为什么 EXPLAIN 显示 type=ALL 却没走索引
这是最典型的“索引失效”表象,但原因往往不是索引建错了,而是查询条件触发了隐式类型转换或函数操作。比如:WHERE user_id = '123'(user_id 是 INT 类型),MySQL 会把字符串 `'123'` 转成整数,但某些版本在转换过程中可能放弃索引;更常见的是 WHERE YEAR(create_time) = 2024——对字段用函数,直接导致索引失效。
实操建议:
- 用
SHOW CREATE TABLE确认字段类型和索引定义,特别注意CHAR/VARCHAR和INT混用场景 - 避免在
WHERE子句中对索引列使用函数、表达式、CAST或运算(如col + 1 = 10) - 用
EXPLAIN FORMAT=TRADITIONAL查看key和key_len是否非NULL,若为NULL,说明压根没选索引 - 留意字符集/排序规则不一致:比如
utf8mb4_bin列和utf8mb4_0900_as_cs连接时,可能因 collation 不兼容跳过索引
LIKE 查询只对后缀模糊才走索引?
是的,但前提是没破坏最左前缀原则。像 WHERE name LIKE 'abc%' 可以用到 (name) 索引;而 WHERE name LIKE '%abc' 或 WHERE name LIKE '%abc%' 基本无法使用 B+Tree 索引(除非启用了全文索引或倒排索引扩展)。
实操建议:
- 联合索引
(a, b, c)下,WHERE a = 1 AND b LIKE 'x%'可用索引,但WHERE a = 1 AND c LIKE '%y'就不行(c不在最左连续段) - 想支持前后模糊查,考虑
FULLTEXT索引 +MATCH ... AGAINST,或引入MyRocks/ClickHouse等支持前缀索引或 ngram 的引擎 - 确认
innodb_ft_min_token_size(默认 3),太短的词不会被全文索引收录
明明有索引,ORDER BY 却触发 Using filesort
这不代表索引完全没用,而是 MySQL 无法同时满足「过滤」和「排序」需求。例如:索引是 (a, b),但查询写成 WHERE a = 1 ORDER BY c(c 不在索引里),就必然要回表或 filesort。
实操建议:
- 如果既要
WHERE又要ORDER BY,优先让排序字段进入联合索引的右侧,如(a, c)支持WHERE a = 1 ORDER BY c - 避免
ORDER BY和WHERE使用不同索引:MySQL 通常只选一个索引,不会合并两个索引 -
SELECT *+ORDER BY容易触发 filesort,因为覆盖索引失效;改用覆盖索引字段列表(如SELECT id, a, c)可消除Using filesort - 注意
ASC/DESC混用:MySQL 8.0+ 支持降序索引,但 5.7 及以前对ORDER BY a ASC, b DESC无法利用(a,b)索引
统计信息不准导致优化器选错索引
MySQL 依赖 INFORMATION_SCHEMA.STATISTICS 和采样数据估算成本,一旦表数据大范围变更(如批量导入、删旧数据),而没触发自动分析,优化器可能误判全表扫描比走索引快,于是弃用索引。
实操建议:
- 执行
ANALYZE TABLE table_name强制更新统计信息(低峰期操作,锁表时间短) - 检查
innodb_stats_auto_recalc是否为ON(默认开启),并确认innodb_stats_persistent启用(避免重启丢失) - 对超大表(>1TB),可调大
innodb_stats_sample_pages(默认 20),提高采样精度 - 用
SELECT * FROM mysql.innodb_table_stats WHERE database_name='db' AND table_name='t'查看最后更新时间
索引是否生效,从来不是“建了就完事”的问题;真正卡住人的,往往是类型隐式转换、统计滞后、或联合索引字段顺序和查询模式不匹配这几个点。排查时先看 EXPLAIN 的 key 和 key_len,再盯住 Extra 里的提示,比反复改 SQL 更有效。










