type=all表示全表扫描,是性能严重隐患;需立即干预,因数据超十万行时响应不可控,应通过explain中key和possible_keys字段组合判断根因,再针对性优化索引或统计信息。

type=ALL 就是没走索引,得立刻干预——不是“可能慢”,而是数据一过十万行,响应就不可控。
怎么一眼确认是不是索引缺失导致的 type=ALL
别猜,直接看 EXPLAIN 输出里对应表的两列:
-
key为NULL且possible_keys也是NULL→ 确实没索引,该建了 -
key为NULL但possible_keys有值(比如idx_user_status)→ 索引存在,但优化器主动弃用,要查统计或成本估算问题 -
key有值(如idx_user_status),type却还是ALL→ 大概率是复合索引顺序错、用了LIKE '%abc'或函数包裹这类失效操作
例如执行 EXPLAIN SELECT * FROM orders WHERE user_id = 123; 后 key 是 NULL,而 user_id 是高频查询字段,那基本就是缺索引。
建索引不是加了就行:顺序、覆盖、类型都得对
单列索引只够应付简单等值查询;一旦带范围、排序或多条件,结构就关键了:
- 等值条件放最左:
WHERE status = 'paid' AND created_at > '2024-01-01',索引应为(status, created_at),反过来效果差很多 - 避免在索引列上用函数:别写
WHERE DATE(created_at) = '2024-01-01',改用WHERE created_at >= '2024-01-01' AND created_at - 覆盖索引能省回表:如果只查
user_id, status, amount,建(user_id, status, amount)后EXPLAIN的Extra会显示Using index - 字段类型必须一致:
user_id是INT,就别传字符串'123',否则隐式转换会让索引失效
加了索引还是 type=ALL?先检查这些隐藏干扰项
常见但容易被忽略的非索引类原因:
- 统计信息过期:
ANALYZE TABLE orders;强制更新行数和分布估算,让优化器重判成本 - optimizer_switch 参数变更:MySQL 8.0 升级后,
mrr=off、index_merge=on等默认值变化可能导致索引被跳过;可用SET SESSION optimizer_switch='mrr=on';临时验证 - 字符集/排序规则不一致:字段是
utf8mb4_unicode_ci,但查询参数用utf8mb4_general_ci,也会让索引失效 - 小表合理走 ALL:若表仅几十行,MySQL 认为全扫比走索引还快,这是正常行为,不用强行干预
真正危险的是中大型表(10 万+ 行)持续出现 type=ALL,这时 I/O 和 CPU 压力会随并发线性上涨,handler_read_rnd_next 指标往往同步飙升。











