type=ALL即全表扫描,表示MySQL未使用索引而逐行读取整张表;无论rows值大小,只要type为ALL就说明存在性能隐患,需结合key、possible_keys和Extra字段综合诊断根因。
type=ALL 就是全表扫描,别信“数据少所以慢得不明显”
只要 type 列显示 all,不管 rows 是 10 还是 1000,都算全表扫描——mysql 正在把整张表从磁盘读一遍。很多人看到 rows=87 就松口气,但这是优化器估算值,不是实际扫描量;真实开销取决于表物理大小、行宽、是否带大字段(如 text)、以及磁盘 i/o 压力。
常见误判场景:
- 表只有几百行,
type=ALL仍可能拖慢高并发查询——因为锁粒度大、缓冲池争用高 -
key列为空,但possible_keys也有空——说明连索引都没建,不是“没选对”,是“根本没得选” -
type=ALL同时Extra出现Using where,代表 WHERE 条件全靠 CPU 过滤,没借力索引
key=NULL 不等于没索引,但等于这次没用上
key 列为 NULL,只说明当前这条 SQL 没走任何索引。它和 possible_keys 的组合才是关键线索:
-
possible_keys有值,key为空 → 索引存在,但被跳过(原因可能是最左前缀不匹配、隐式类型转换、函数包裹字段,比如DATE(create_time) = '2023-01-01') -
possible_keys也为空 → 索引大概率缺失,立刻查SHOW INDEX FROM table_name确认 - Navicat 还原数据库后高频出这个问题:.nb3 备份不存索引 DDL,还原完必须手动补
CREATE INDEX
rows 值小 ≠ 安全,要看它和实际返回行数的比值
rows 是优化器预估扫描行数,不是结果集大小。如果 SELECT COUNT(*) 返回 12 行,而 rows=5600,说明 MySQL 认为要扫 5600 行才能凑够这 12 行——大概率是索引没覆盖查询条件,或统计信息过期。
- 执行
ANALYZE TABLE table_name更新统计信息,再看rows是否回落 - 若
rows仍远高于实际,检查 WHERE 字段是否都在索引里,且顺序匹配最左前缀 - 注意:即使
rows=1,只要type=ALL,仍是全表扫描——只是恰好第一行就命中,不可依赖
Extra 里的 Using filesort / Using temporary 是红灯信号
这两个提示不是“建议优化”,而是“已确定性能瓶颈”。它们和 type=ALL 经常并存,但即使 type 是 range 或 ref,只要 Extra 出现它们,排序或分组过程就脱离了索引能力。
-
Using filesort:ORDER BY 字段没索引,或索引无法覆盖排序需求(例如ORDER BY a ASC, b DESC,但索引是(a,b)) -
Using temporary:GROUP BY、DISTINCT 或子查询触发临时表,通常因缺少复合索引或字段类型不一致(如VARCHAR字段用数字字面量比较) - 别指望加个索引就解决——要建能同时支撑 WHERE + ORDER BY + GROUP BY 的复合索引,字段顺序必须严格按使用优先级排列
type=ALL 当成孤立现象去处理。它往往和 key=NULL、rows 失真、Extra 报警联动出现,背后通常是索引设计与查询写法的错位。动手前先确认索引是否存在、字段类型是否一致、WHERE 条件是否可索引化——比调优单条 SQL 更重要。


















