type=all表示全表扫描,必须立即优化:优先检查key是否为null以确认索引缺失,否则排查联合索引顺序、隐式转换、前缀索引失效等导致索引未被选用的原因,并建立符合等值→范围→排序顺序的联合索引。

当 EXPLAIN 输出中 type = ALL,说明这条 SQL 正在做全表扫描——这不是“可能慢”,而是已经处于性能红区。优化核心就一条:让 MySQL 用上索引,把 ALL 变成 ref、range 或更好。
先确认是不是真没索引可用
看 key 字段是否为 NULL:
- 如果是
NULL,说明连索引都没建,直接补联合索引 - 如果
key有值(比如idx_status_created),但type还是ALL,说明索引存在却没被选中,得查原因
常见“有索引却不走”的情况包括:联合索引顺序错(如索引是 (status, created_at),但查询只写了 WHERE created_at > '2024-01-01');字符串字段用了前缀索引但查询值太短(如 INDEX(title(10)),却查 title = 'a');或字段类型隐式转换(比如 user_id 是 VARCHAR,但 WHERE user_id = 123 传了数字)。
按查询条件结构建联合索引
别堆单列索引。MySQL 在一个查询里通常只用一个索引(index_merge 不稳定且开销大)。要建就建联合索引,并严格按这个顺序排列:
-
等值字段放最左(
=、IN),越多越好,例如user_id = 123 AND status = 'paid' -
范围字段最多一个,紧接在等值之后(
>、、<code>BETWEEN),例如amount > 100 -
排序或分组字段可追加其后(避免
Using filesort),例如ORDER BY created_at DESC
示例:查询 WHERE user_id = 123 AND status = 'paid' AND amount > 100 ORDER BY created_at DESC,最优索引是 (user_id, status, amount, created_at)。把 amount 放 status 前面,等值筛选能力就废了。
警惕前缀索引和模糊匹配的陷阱
前缀索引不是万能解药:
-
LIKE '%abc'(前导通配符)必然导致type = ALL,B+ 树无法从根节点向下定位,前缀索引也一样失效 - 建前缀索引前先看区分度:
SELECT COUNT(DISTINCT LEFT(title, 20)) / COUNT(*) FROM articles;结果低于 0.9 就别设太短 - 检查
key_len是否接近你定义的前缀长度;若远小于(如定义title(50),但key_len显示 30),可能是字符集或排序规则导致截断
验证与轻量修复优先于重建
不要一上来就 ALTER TABLE ... ENGINE=InnoDB 全表重建:
- 先跑
ANALYZE TABLE table_name;更新统计信息——90% 的“走错索引”问题靠它就能解决 - 用
SHOW INDEX FROM table_name;确认索引定义,特别是Sub_part列是否存在(有值即为前缀索引) - 真正需要重建索引的信号很明确:统计信息严重失真(
Cardinality长期为 0)、大量删除后data_free占比超 25%、或错误日志报索引损坏 - MySQL 8.0.12+ 可精准重建二级索引:
ALTER TABLE t ALTER INDEX idx_name REBUILD;,不碰主键,也不锁写入太久











