最关键看type、key、rows、extra四字段:type=all/index表示全表扫描需警惕,key为空说明索引失效,rows远大于结果行数反映扫描低效,extra含using filesort或temporary提示排序/临时表开销。

EXPLAIN 输出里哪些字段最关键
看懂 EXPLAIN 的核心不是背全字段,而是盯住 type、key、rows、Extra 这四个。它们直接暴露查询是否走索引、扫描多少行、有没有临时表或文件排序。
-
type值为ALL或index时基本等于全表扫描,得立刻查原因;range、ref、const才算合理 -
key为空说明没用上索引,哪怕表上有索引也可能因类型不匹配或函数包裹失效 -
rows是 MySQL 预估扫描行数,比实际结果集大很多(比如预估 10 万,返回 10 行)往往意味着索引没起到过滤作用 -
Extra出现Using filesort或Using temporary就是性能红灯,尤其在ORDER BY或GROUP BY场景下
为什么加了索引,EXPLAIN 还显示 type=ALL
常见原因是索引字段在查询条件中被隐式转换或函数操作,导致无法使用 B+ 树索引的最左前缀匹配规则。
- 字符串字段用数字比较:
WHERE user_id = 123(user_id是VARCHAR)→ 触发隐式类型转换,索引失效 - 对索引字段用函数:
WHERE DATE(created_at) = '2024-01-01'→created_at上的索引完全无效 - 联合索引顺序错:
INDEX(a,b,c),但查询只用了WHERE c = 1→ 不满足最左前缀,索引不可用 - 字符集/排序规则不一致:关联表字段字符集不同,即使都有索引也会退化为全表扫描
如何用 EXPLAIN 分析 JOIN 性能瓶颈
MySQL 关联顺序由优化器决定,EXPLAIN 的 table 列顺序就是实际驱动表顺序,第一行通常是驱动表(小结果集优先),后续是被驱动表。
- 如果
type为ALL出现在被驱动表(非第一行),说明缺少关联字段索引,必须给ON条件中的外键字段加索引 -
rows值在 JOIN 后急剧放大(比如从 100 跳到 50000),大概率是驱动表结果集过大,需先缩小驱动表范围(加更严格的 WHERE) -
Extra出现Using join buffer (Block Nested Loop)是内存不足 fallback 到磁盘连接,应调高join_buffer_size或优化关联逻辑
EXPLAIN FORMAT=JSON 比传统格式多什么信息
传统 EXPLAIN 只给概览,EXPLAIN FORMAT=JSON 提供代价估算、访问方法选择依据和具体索引使用细节,适合定位“为什么没选某个索引”这类问题。
- 看
query_cost字段,对比不同写法的成本值,比单纯看rows更可靠 -
used_range_access_grants明确列出哪些索引被考虑过,以及被拒绝的原因(如 “Index is not applicable for the condition”) -
attached_condition展示 WHERE 中哪些条件下推到了存储引擎层,哪些留在 Server 层过滤 - 注意:JSON 输出里
key字段可能为空,但possible_keys有值——说明索引存在,但优化器评估后认为成本更高而放弃
复杂查询别只看一行 rows,要结合驱动顺序、索引实际命中情况和代价模型一起读。很多人卡在“明明建了索引却没用”,其实问题常出在数据分布倾斜或统计信息过期,ANALYZE TABLE 有时比改 SQL 更快见效。











