type为all即全表扫描,表明mysql遍历整表匹配条件且未用有效索引;常见原因包括字段无索引、使用函数、隐式转换、like左模糊等。

EXPLAIN 的 type 列值为 ALL 就是全表扫描
这是最直接的判断依据。只要 EXPLAIN 输出里 type 这一列显示 ALL,说明 MySQL 正在遍历整张表的每一行来匹配条件,没有用上有效索引。
常见错误现象:type: ALL 却误以为“只是没走主键”,其实和是否主键无关——哪怕 WHERE 条件写的是 id = 123,如果 id 列没建索引,照样是 ALL。
-
type值从好到坏大致是:system≈const>eq_ref>ref>range>index>ALL -
index看起来比ALL好,但它仍是全索引扫描(可能比全表还慢,尤其当索引比表大时) - 注意
type: index和type: ALL都属于“扫描类”,不是“查找类”,性能风险类似
为什么 type 是 ALL?先看 WHERE 条件是否命中索引
绝大多数 ALL 都是因为 WHERE 子句无法利用现有索引,而不是 SQL 写得“丑”。关键看字段、操作符、函数三者是否破坏了索引可用性。
- 字段没建索引:比如
WHERE status = 'active',但status列没索引 - 用了函数或表达式:
WHERE YEAR(created_at) = 2024—— 索引失效,created_at上的 B+ 树无法直接跳转 - 隐式类型转换:
WHERE user_id = '123',而user_id是INT类型,MySQL 会把每行都转成字符串比对 - LIKE 左模糊:
WHERE name LIKE '%abc',B+ 树只能从左前缀匹配,没法跳过开头
EXPLAIN 的 key 和 possible_keys 要一起看
type: ALL 时,key 列一定是 NULL,但光看 key 不够——得对照 possible_keys 是否为空。
- 如果
possible_keys有值(比如idx_status),但key是NULL,说明优化器认为走这个索引反而更慢(比如它预估要回表太多次) - 如果
possible_keys也是NULL,那基本就是没索引可用,优先加索引 - 注意:有些情况
possible_keys显示了索引,但key是NULL,且rows很大,这时可以强制指定索引测试:SELECT ... FROM t USE INDEX (idx_status) WHERE ...
小表不等于可以容忍 ALL,尤其在 JOIN 或高并发场景下
有人觉得“才 1 万行,ALL 也很快”,但问题不在单次查询耗时,而在资源争用和可扩展性。
- JOIN 时一张小表
ALL,会导致被驱动表反复扫描(N × M 次逻辑读),放大 IO 压力 - 高并发下,多个线程同时做全表扫描,容易挤占 buffer pool,把热数据刷出去
- 即使现在快,一旦业务增长、字段变多、字符集变宽,
rows增长带来的性能拐点会来得比预期早
真正难识别的不是 type: ALL,而是那些 type: index 却扫了几十万行的“伪高效”查询——它们更容易被忽略,但同样吃内存、卡 CPU、拖慢整体 QPS。











