explain显示type=all但key不为空,说明索引存在但未被优化器选用,常见原因包括联合索引未满足最左前缀、前缀索引长度不足、字符串字段隐式转换或统计信息过期。

EXPLAIN显示type=ALL,但key不为空,为什么索引没生效
这说明索引存在,但优化器没选它——常见于联合索引顺序错、前缀长度不足或查询条件未命中索引最左前缀。比如建了(status, created_at),却查WHERE created_at > '2024-01-01',那created_at根本不在最左位置,索引直接失效。
另一个典型是字符串字段用了前缀索引但查询值太短:INDEX idx_title (title(10)),而WHERE中匹配的是title = 'a'(长度1),MySQL无法用前缀索引做等值查找,退化为ALL。
- 检查
EXPLAIN的key_len:若远小于你定义的前缀长度(如定义title(50),但key_len只显示30),说明只用了前30字节,可能因字符集或排序规则截断 - 用
SHOW INDEX FROM table_name确认索引定义是否含Sub_part值,有值即为前缀索引 - 对
VARCHAR字段建前缀索引前,先跑SELECT COUNT(DISTINCT LEFT(title, 20)) / COUNT(*) FROM table_name看区分度;低于0.9就别设太短
WHERE里有多个AND条件,该建单列索引还是联合索引
单列索引在多条件AND下基本无效——MySQL一般只用一个索引,除非开启index_merge(且不稳定、开销大)。必须建联合索引,且顺序严格按“等值 → 范围 → 排序/分组”排列。
例如查询WHERE user_id = 123 AND status = 'paid' AND amount > 100 ORDER BY created_at DESC,最优索引是(user_id, status, amount, created_at)。把amount放status前面就废了等值部分的筛选能力。
- 等值字段(
=、IN)必须放最左,越多越好 - 范围字段(
>、、<code>BETWEEN)只能有一个,且必须放在等值字段之后 -
ORDER BY字段可接在范围字段后,但仅当它和查询条件共用同一索引时才避免Using filesort
LIKE '%abc'导致type=ALL,前缀索引能解决吗
不能。LIKE带前导通配符(%开头)时,任何B+树索引都失效,前缀索引也一样。MySQL没法从索引树根往下定位,只能全扫。
真要支持模糊前缀搜索,得换方案:FULLTEXT索引(适合中文需搭配ngram)、GENERATED COLUMN + 索引(如提取URL域名建索引),或引入Elasticsearch。
- 如果业务允许,把
LIKE '%abc'改成LIKE 'abc%',再配合普通索引或前缀索引即可生效 - 用
LEFT(col, N)提取固定前缀建索引,适用于“取文件扩展名”“取域名”这类确定性场景 - 别在
WHERE里对索引列用LOWER()、TRIM()等函数,它们和LIKE '%xxx'一样直接让索引失效
建了联合索引,EXPLAIN还是显示type=ALL,下一步查什么
先排除统计信息过期和隐式转换这两类“看不见的坑”。哪怕索引结构完美,优化器也可能因误判行数或类型不一致而弃用它。
- 执行
ANALYZE TABLE table_name强制更新统计信息,尤其在大批量INSERT/DELETE后 - 用
SHOW CREATE TABLE table_name核对字段类型,再比对查询参数:比如字段是VARCHAR(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci,但应用传参用了utf8mb4_general_ci,就会触发隐式转换 - 检查
EXPLAIN FORMAT=TREE(MySQL 8.0+)输出里的rows_examined_per_scan预估值,若远高于实际匹配行数,说明统计不准或数据倾斜严重
真正难啃的往往是那些“加了索引也ALL”的情况——不是索引没建对,而是优化器在说:这张表我扫起来比走索引还快。这时候得看Handler_read_rnd_next和Innodb_buffer_pool_reads,确认是不是缓存全命中、纯CPU遍历,而非IO瓶颈。











