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 如何查找表中的行。从最优到最差依次为:systemconsteq_refrefrangeindexALL。理想情况下应至少达到 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_keyskey 列判断是否合理使用了索引。

  • 分析查询顺序‌:id 列可以清晰地反映出查询的执行顺序。

  • 识别性能瓶颈‌:Extra 中的 Using filesortUsing temporary 可能意味着需要优化排序或分组操作。

4. MySQL 8.0+ 新特性

  • EXPLAIN ANALYZE‌:在 MySQL 8.0 及以上版本中,可以通过 EXPLAIN ANALYZE 实际执行 SQL 并统计时间,更精准地分析性能瓶颈。

  • FORMAT=TREE‌:以树形结构展示执行流程,便于理解查询块层级与成本估算。

Logo

AtomGit 是由开放原子开源基金会联合 CSDN 等生态伙伴共同推出的新一代开源与人工智能协作平台。平台坚持“开放、中立、公益”的理念,把代码托管、模型共享、数据集托管、智能体开发体验和算力服务整合在一起,为开发者提供从开发、训练到部署的一站式体验。

更多推荐