type=all表示mysql执行全表扫描,即未使用索引、逐行读取整张表;常见原因包括无索引、索引顺序错配、函数包裹字段、隐式类型转换及统计信息过期。

点“解释”按钮后看到 type=ALL 就是全表扫描
Navicat 里判断是否发生全表扫描,最直接的依据就是执行计划中 type 列的值为 ALL。这不是警告,而是明确结论:数据库没走索引,正一行行读完整张表。
常见诱因包括:
-
WHERE条件字段没建索引,或索引字段顺序与查询条件不匹配(比如索引是(a,b),但只查b = ?) - 对索引字段用了函数或表达式,如
YEAR(create_time) = 2023、UPPER(name) = 'ABC' - 隐式类型转换,比如字段是
VARCHAR,但传入数字参数:user_id = 123(而user_id实际是字符串类型) - 使用了
OR连接多个非索引字段,或!=、NOT IN等难以利用索引的操作
possible_keys 有值但 key 为空,说明索引被“看见”却没被选中
这比完全没索引更值得细看——优化器明明知道有可用索引(possible_keys 显示了候选索引),却放弃使用(key 为空),往往是因为统计信息过期、索引选择性差,或查询条件导致优化器误判成本更低。
实操建议:
- 先运行
ANALYZE TABLE table_name更新统计信息(MySQL),让优化器重新评估 - 检查该索引是否覆盖了查询中所有
WHERE和ORDER BY字段;若ORDER BY字段不在索引中,可能触发Using filesort,进而让优化器放弃索引 - 用
EXPLAIN FORMAT=JSON查看详细成本估算(Navicat Premium 支持),重点关注cost_info中的query_cost和各访问路径对比
对比 rows 和实际结果集大小,确认扫描是否失控
rows 是 MySQL 预估要扫描的行数,不是返回行数。如果 rows 是 50 万,但最终只返回 10 行,基本可断定存在严重冗余扫描——要么索引失效,要么条件过滤能力极弱。
注意两个易忽略点:
-
rows值来自采样估算,不一定准;若表刚大批量写入或长期未ANALYZE,该值可能严重偏离真实情况 - 多表 JOIN 时,
rows是单表预估,叠加后实际 I/O 可能呈指数增长;此时更要盯紧驱动表的type和rows - Navicat 的“解释”默认发的是
EXPLAIN,不是EXPLAIN ANALYZE(PostgreSQL)或EXPLAIN FORMAT=TREE(MySQL 8.0.16+),它不反映真实执行耗时或实际扫描行数
别只盯着 type,Extra 里的 Using temporary 和 Using filesort 往往是全表扫描的伴生问题
这两个标记本身不等于全表扫描,但它们和 type=ALL 同时出现时,说明查询不仅扫得广,还干了额外重活:排序或分组被迫落盘,进一步放大性能损耗。
典型场景:
-
ORDER BY字段未包含在索引中,或索引顺序与ORDER BY不一致(如索引是(a, b),却ORDER BY b, a) -
GROUP BY没命中索引,且数据量大到无法在内存完成聚合 -
DISTINCT或UNION触发去重逻辑,又无合适索引支撑
真正难调的 case,往往不是单个 ALL,而是 type=ALL + Extra=Using temporary; Using filesort 的组合——这时光加索引不够,得重写逻辑或拆分查询。











