MySQL的EXPLAIN通过type、rows、key、Extra四字段定位80%查询瓶颈:type为ALL/index需建索引,rows过大说明索引失效,key为NULL或key_len异常表明未用索引或违反最左前缀,Extra中Using filesort/temporary提示排序/临时表问题。

MySQL 的 EXPLAIN 是排查慢查询、优化 SQL 性能最直接的工具。PHP 中执行 SQL 前加 EXPLAIN,能快速看清 MySQL 如何执行这条语句——但结果字段多、含义隐晦,容易看错关键点。
重点关注 type 和 rows 字段
type 表示连接类型,直接影响效率。从好到差大致是:system ≈ const > eq_ref > ref > range > index > ALL。其中 ALL 代表全表扫描,必须优化;index 是全索引扫描,虽比 ALL 快些,但数据量大时仍危险。
rows 是 MySQL 预估需要扫描的行数,并非实际返回行数。如果 rows 远大于最终结果集(比如查 10 条却要扫 50 万行),说明索引没用好或条件选择性差。
- 当
type是ALL或index,先检查WHERE条件字段是否建了索引 - 若
rows异常高,尝试用SELECT COUNT(*)验证实际匹配行数,判断预估是否偏差过大 - 联合索引要注意最左前缀原则:查询只用到索引中间字段(如索引是
(a,b,c),但 WHERE 只有b = ?),type 很可能退化为index或ALL
留意 key 和 key_len,确认索引是否真正生效
key 显示实际使用的索引名。如果为 NULL,说明没走索引(即使表上有索引);如果显示索引名,再看 key_len 判断用了索引的几个字段。
立即学习“PHP免费学习笔记(深入)”;
key_len 是索引使用长度(单位字节),可据此反推用了哪些列。例如字段 name VARCHAR(50) 用 utf8mb4 编码,单字符占 4 字节,若 key_len = 200,说明该索引前 50 个字符全被用于查找(50 × 4 = 200);若只有 100,可能只用到了前 25 个字符,或索引定义本身只包含部分字段。
- 对比
key和建表时的SHOW INDEX结果,确认是不是你预期的索引 -
key_len值偏小,可能是条件中对索引字段用了函数(如WHERE UPPER(name) = 'ABC')或模糊查询(LIKE '%abc'),导致索引失效 - 联合索引中,
key_len能帮你验证是否满足最左前缀:比如索引(a, b, c),key_len对应 a+b 的长度,说明 c 没参与查找
Extra 字段藏着关键线索
Extra 是补充信息,很多性能问题就藏在这里:
-
Using filesort:MySQL 需额外排序,常见于ORDER BY字段没走索引。解决办法是让排序字段加入联合索引末尾(如查询WHERE a = ? ORDER BY b,索引设为(a, b)) -
Using temporary:创建临时表,多见于 GROUP BY、DISTINCT 或含子查询的复杂语句。尽量避免在大表上做这类操作,或考虑加覆盖索引 -
Using index:好消息,表示走了覆盖索引(所需字段全在索引里),不用回表查数据行 -
Using where:正常现象,表示 MySQL 在存储引擎层后又做了条件过滤;但如果同时出现Using index,说明是索引下推(ICP),效率更高
在 PHP 中高效使用 EXPLAIN
别只在开发环境手动贴 SQL 查看。可在 PHP 日志或调试面板中自动追加 EXPLAIN:
- 封装一个
explainQuery($sql, $params)方法,在慢查询日志触发时自动执行并记录结果 - 对 PDO 查询,可在
prepare()后、execute()前插入EXPLAIN前缀,再 fetch 结果分析 - 注意:EXPLAIN 不执行语句,不锁表,但频繁调用也影响性能,建议仅在调试或监控慢查询时启用
- 生产环境慎用
EXPLAIN FORMAT=JSON,虽然信息更全,但解析成本略高,且 PHP 默认 fetch 不友好
不复杂但容易忽略。把 type、rows、key、Extra 四个字段串起来看,基本就能定位 80% 的查询性能瓶颈。











