
EXPLAIN 是分析 SQL 执行效率最直接的工具,它不真正执行语句,而是返回数据库优化器预估的执行路径。关键不是看“有没有用上索引”,而是理解 数据如何被检索、连接、过滤和排序,再结合实际数据分布与索引结构做针对性调整。
读懂 EXPLAIN 输出的核心字段
以 MySQL 为例,重点关注以下几列:
- type:连接类型,从好到差大致为 const ≈ eq_ref > ref > range > index > ALL。出现 ALL(全表扫描)或 index(全索引扫描)需警惕,尤其在大表上
- key:实际使用的索引名。为 NULL 表示未走索引,可能因条件不匹配、隐式类型转换、函数包裹字段等导致
- rows:优化器预估需要扫描的行数。该值远大于实际返回结果行数(如查 10 行却扫 10 万行),说明筛选效率低,索引选择或条件写法可能有问题
- Extra:常见不利提示包括 Using filesort(需额外排序)、Using temporary(建临时表)、Using join buffer(块嵌套连接回退)——这些往往意味着缺失合适的联合索引或排序字段未被索引覆盖
常见低效模式与对应优化方向
很多性能问题有典型诱因,可快速定位:
-
WHERE 条件中对索引字段使用函数或运算:例如
WHERE YEAR(create_time) = 2024会让索引失效。应改写为范围查询:WHERE create_time BETWEEN '2024-01-01' AND '2024-12-31' -
LIKE 左模糊:
WHERE name LIKE '%abc'无法利用索引。若业务允许,尽量改为右模糊LIKE 'abc%';否则考虑全文索引或倒排表 -
OR 连接多个非索引字段:如
WHERE a = 1 OR b = 2,且 a、b 单独有索引但无联合索引,可能导致全表扫描。可拆成 UNION 查询,或建立(a,b)覆盖索引(视查询需求而定) -
ORDER BY 与 WHERE 不共用索引:例如
WHERE status = 1 ORDER BY created_at,若只有status索引,排序将触发 Using filesort。应建立联合索引(status, created_at)
联合索引设计与最左前缀原则验证
联合索引不是简单把字段堆在一起,必须符合查询条件的实际使用顺序:
- 索引
(a, b, c)可用于WHERE a = ?、WHERE a = ? AND b = ?、WHERE a = ? AND b = ? AND c = ?,也可用于WHERE a = ? ORDER BY b - 但不能用于
WHERE b = ?或WHERE b = ? AND c = ?(跳过最左列),也不能高效支持WHERE a = ? ORDER BY c(中间断开) - 用 EXPLAIN 验证:添加索引后再次执行,观察 key 是否命中、rows 是否显著下降、Extra 是否消失 Using filesort 或 Using temporary
执行计划并非绝对,需结合真实数据验证
EXPLAIN 显示的是优化器“预测”,实际性能受数据倾斜、统计信息陈旧、缓存状态等影响:
- 执行
ANALYZE TABLE table_name更新表统计信息,避免优化器误判 - 用
SELECT ... INTO DUMPFILE或慢日志中的 Query_time 和 Rows_examined 对比 EXPLAIN 的预估值 - 对复杂查询,可分步 EXPLAIN 子查询或临时表,避免被外层操作掩盖内层瓶颈










