MySQL 的 `EXPLAIN` 命令
MySQL 的 EXPLAIN 命令是用于分析 SQL 查询语句执行计划的重要工具,它可以帮助开发者理解查询的执行过程、判断是否存在性能瓶颈,并指导优化查询语句。通过在 SQL 语句前加上 EXPLAIN 关键字,MySQL 会返回一个执行计划的表格,展示查询优化器如何处理该语句。
1. EXPLAIN 的基本用法
使用 EXPLAIN 非常简单,只需在 SELECT 语句前加上 EXPLAIN 关键字即可。例如:
EXPLAIN SELECT * FROM users WHERE age > 18;
执行后,MySQL 会返回一张包含执行计划信息的表格。
2. EXPLAIN 输出列详解
EXPLAIN 的输出结果包含多个列,每个列都有其特定含义:
-
id:表示查询中每个操作的标识符,反映了查询中各个子查询或表的执行顺序。当
id相同时,执行顺序由上至下;当id不同时,id值越大,优先级越高。 -
select_type:表示查询类型,如
SIMPLE(简单查询)、PRIMARY(最外层查询)、SUBQUERY(子查询)、DERIVED(派生表)等。 -
table:当前行访问的表名,如果查询包含子查询或
UNION,则可能显示临时表。 -
type:访问类型,表示 MySQL 如何查找表中的行。从最优到最差依次为:
system、const、eq_ref、ref、range、index、ALL。理想情况下应至少达到range,最好为ref。访问类型 含义说明 典型场景 性能等级 system 表仅有一行数据(如系统表),是 const 的特例 查询 MySQL 系统表或单行 MyISAM 表 ⭐⭐⭐⭐⭐(最优) const 通过主键或唯一索引等值匹配,最多返回一行 WHERE id = 1(id 为主键) ⭐⭐⭐⭐⭐ eq_ref 在连接查询中,被驱动表通过主键或唯一索引进行等值关联 JOIN 时关联主键字段 ⭐⭐⭐⭐☆ ref 使用非唯一索引进行等值匹配,可能返回多行 WHERE index_col = 'value' ⭐⭐⭐☆☆ range 通过索引检索指定范围内的行 WHERE age > 18 或 IN (1,2,3) ⭐⭐☆☆☆ index 全索引扫描,遍历整个索引树 覆盖索引但需扫描全部索引项 ⭐☆☆☆☆ ALL 全表扫描,未使用索引 无索引字段查询或未命中索引 ☆☆☆☆☆(最差) -
possible_keys:列出查询可能使用的索引。
-
key:实际使用的索引。如果为
NULL,表示未使用索引。 -
key_len:使用的索引长度,单位为字节。越短表示使用的索引列越少。
-
ref:显示索引列与哪一列或常量进行比较。
-
rows:预估需要扫描的行数,越小越好。
-
filtered:按条件过滤出的行数的百分比。
-
Extra:额外的信息,如
Using index(覆盖索引)、Using where(使用 WHERE 过滤)、Using temporary(使用临时表)等。Extra 值 含义说明 上下文关联与性能影响 优化建议 Using index 使用了覆盖索引,即查询所需字段全部包含在索引中,无需回表查询数据行 。 通常出现在 type 为 index 或 ref 的情况下,性能很好 。若 type=ALL 却出现此值,说明虽未命中高效访问方式,但至少避免了磁盘 I/O。 保持现状;可进一步精简索引长度(key_len)提升效率。 Using where MySQL 在存储引擎层检索出数据后,还需在服务器层进行 WHERE 条件过滤 。 若 type=ALL 或 index,常伴随此值,表明未有效利用索引过滤。但若 type=ref 或 range,则属正常现象 。 检查是否可通过添加复合索引将过滤条件下推至存储引擎。 Using temporary 查询需要创建临时表来处理结果,常见于 GROUP BY、DISTINCT 或 ORDER BY 与 GROUP BY 字段不一致的情况 。 性能开销大,尤其在大数据集上。若同时 type=ALL,问题更严重。 为 GROUP BY 或 DISTINCT 字段添加索引;避免对非索引字段排序。 Using filesort MySQL 需要额外的排序操作,无法利用索引的有序性完成 ORDER BY 或 GROUP BY 。 即使 type=ref,出现此值也意味着排序成本高。理想情况应通过索引消除排序。 为 ORDER BY 字段建立索引,或与 WHERE 条件组合建立联合索引。 Using index condition 启用了索引下推(ICP),MySQL 在存储引擎层就对索引进行条件过滤,减少回表次数 。 出现在 range 查询中,是一种优化行为,说明 MySQL 正在高效利用索引。 无需优化,这是良好实践的体现。 Range checked for each record (index map: N) 没有合适的固定索引可用,MySQL 对每一行记录动态评估可用索引范围 。 多表连接时出现,通常意味着连接字段缺乏有效索引,性能较差。 检查连接字段是否建立了索引,特别是 ON 条件中的列。 Impossible WHERE 查询条件矛盾,MySQL 判断无需读取任何行即可返回空结果集。 虽然执行快,但可能是逻辑错误导致,需确认业务意图。 核实 SQL 逻辑是否正确,避免误写条件。 Distinct MySQL 在找到第一个匹配的唯一值后即停止扫描,用于优化 DISTINCT 查询 。 表明查询已被优化,通常与 Using index 同时出现,性能良好。 可结合覆盖索引进一步提升效率。
3. 使用场景与优化建议
-
发现全表扫描:如果
type显示为ALL,说明存在全表扫描,应考虑添加索引。 -
判断索引使用情况:通过
possible_keys和key列判断是否合理使用了索引。 -
分析查询顺序:
id列可以清晰地反映出查询的执行顺序。 -
识别性能瓶颈:
Extra中的Using filesort或Using temporary可能意味着需要优化排序或分组操作。
4. MySQL 8.0+ 新特性
-
EXPLAIN ANALYZE:在 MySQL 8.0 及以上版本中,可以通过
EXPLAIN ANALYZE实际执行 SQL 并统计时间,更精准地分析性能瓶颈。 -
FORMAT=TREE:以树形结构展示执行流程,便于理解查询块层级与成本估算。
AtomGit 是由开放原子开源基金会联合 CSDN 等生态伙伴共同推出的新一代开源与人工智能协作平台。平台坚持“开放、中立、公益”的理念,把代码托管、模型共享、数据集托管、智能体开发体验和算力服务整合在一起,为开发者提供从开发、训练到部署的一站式体验。
更多推荐



所有评论(0)