type=ALL表示全表扫描,即未使用索引、逐行匹配;常见原因包括无索引、函数操作、隐式转换或OR多非索引字段;可通过EXPLAIN的key和possible_keys快速定位索引缺失问题。

type=ALL 表示正在全表扫描
MySQL 执行计划里 type 字段为 ALL,说明这条查询没走任何索引,引擎正逐行读取整张表来匹配条件。这不是“慢一点”,而是数据量一上去就线性恶化——10 万行可能还凑合,100 万行就明显卡顿,千万级基本不可用。
常见触发场景:WHERE 条件字段没索引、用了函数(如 WHERE YEAR(create_time) = 2023)、隐式类型转换(如字符串字段传数字查)、或者 OR 连接多个非索引字段。
怎么快速确认是不是索引缺失导致的 ALL
别猜,直接看 EXPLAIN 输出里的 key 和 possible_keys 字段:
-
key为空,possible_keys也为空 → 没可用索引,得加 -
key为空,但possible_keys有值 → 索引存在,但优化器认为不划算(比如筛选率太高,走索引反而更慢) -
key有值,但type还是ALL→ 可能是复合索引顺序不对,或用了LIKE '%xxx'这类无法利用索引前缀的情况
执行 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,性能提升明显
别盲目给所有 WHERE 字段都建索引——写多读少的表,索引维护成本会拖慢 INSERT/UPDATE。
type=ALL 不一定全是索引的事
有时候加了索引也还是 ALL,得排查其他干扰项:
- 统计信息过期:
ANALYZE TABLE orders;强制更新表的行数和分布估算,让优化器重判 - 小表默认走 ALL:如果表只有几十行,MySQL 认为全扫比走索引还快,这是合理行为,不用强行干预
- 字符集/排序规则不一致:比如字段是
utf8mb4_unicode_ci,但查询时传了utf8mb4_general_ci的参数,会导致索引失效 -
SQL_NO_CACHE或查询缓存关闭影响不大,但FORCE INDEX可临时验证索引是否真有效:SELECT * FROM orders FORCE INDEX (idx_user_status) WHERE user_id = 123;
真正难的不是加索引,是判断该加哪几个、顺序怎么排、以及什么时候不该加——尤其当 WHERE 条件动态拼接、字段组合多变时,单靠一个索引很难覆盖全部路径。


















