explain 显示查询执行计划而非结果,关键字段含 id、type(all 表示全表扫描需排查)、key(null 说明未用索引)、rows(预估扫描行数,越大越差)、extra(using filesort/temporary 意味着性能隐患);加索引未生效常因函数操作等导致优化器弃用索引。

EXPLAIN 输出字段怎么看
MySQL 的 EXPLAIN 不是告诉你“查到了什么”,而是告诉你“打算怎么查”。关键字段包括 id、type、key、rows、Extra。其中 type 值从好到差通常是:system ≈ const > eq_ref > ref > range > index > ALL;出现 ALL 意味着全表扫描,要优先排查。
key 显示实际用到的索引名,为 NULL 说明没走索引;rows 是 MySQL 预估需要扫描的行数(不是结果行数),值越大越危险;Extra 里出现 Using filesort 或 Using temporary 通常意味着排序或分组没走索引,性能开销大。
为什么加了索引还是没走
常见原因不是索引没建,而是查询写法或数据分布导致优化器放弃使用。比如:
-
WHERE条件对字段用了函数,如WHERE YEAR(create_time) = 2023→ 改成WHERE create_time >= '2023-01-01' AND create_time - 隐式类型转换,如
user_id是INT,但写成WHERE user_id = '123'→ 字符串字面量触发转换,可能使索引失效 - 索引列在
OR左右两侧,且只有一侧有索引 → 尝试改用UNION或确保两边都有对应索引 - 统计信息过期,执行
ANALYZE TABLE table_name更新即可
如何看 JOIN 的执行顺序和效率
EXPLAIN 的 id 列决定执行顺序:相同 id 表示同一级操作,并按出现顺序执行;不同 id 中数字越小越先执行。对于 JOIN,MySQL 一般从小结果集驱动大表(即“驱动表”在 EXPLAIN 中排第一),但若驱动表没有合适索引,就会变成嵌套循环全扫。
检查点:
- 确认被驱动表的
ON条件字段是否走了索引(看key和type) - 避免
SELECT *,尤其在多表 JOIN 时,字段越多,临时表/缓冲区压力越大 - 如果
Extra出现Using join buffer (Block Nested Loop),说明没走索引,正退化为慢速连接方式
EXPLAIN SELECT u.name, o.amount FROM users u JOIN orders o ON u.id = o.user_id WHERE u.status = 'active';
EXPLAIN FORMAT=JSON 能看到什么额外信息
默认的表格输出太简略。EXPLAIN FORMAT=JSON 会返回结构化 JSON,包含更细粒度的决策依据,比如:
-
used_columns:该表实际参与查询的列(帮你发现冗余字段) -
condition_filtering_pct:条件过滤率预估,低于 10% 可能说明选择性差 -
attached_condition:下推到存储引擎层的 WHERE 条件,有助于判断索引是否被充分利用 -
query_cost:优化器估算的总成本,可用于横向对比两种写法的代价
注意:FORMAT=JSON 不支持所有 MySQL 版本(5.6+ 开始支持,但 5.7 才较稳定),且无法直接用于生产慢查监控——它本身不记录执行时间,只是计划预估。
最常被忽略的一点:EXPLAIN 不执行语句,也不反映锁行为、MVCC 版本链长度、buffer pool 命中率等运行时状态。真正卡顿的查询,光看 EXPLAIN 往往不够。










