MySQL EXPLAIN详细解析

 更新时间:2025年11月10日 10:19:19   作者:Java 码农  
EXPLAIN是SQL性能优化的关键工具,它展示了MySQL如何执行一条SQL 语句,通过分析它的结果,你可以找出查询的瓶颈并进行优化,本文结合实例代码给大家介绍的非常详细,感兴趣的朋友跟随小编一起看看吧

EXPLAIN 是 SQL 性能优化的关键工具,它展示了 MySQL 如何执行一条 SQL 语句。通过分析它的结果,你可以找出查询的瓶颈并进行优化。

下面我将对 EXPLAIN 进行详细解析。

一、什么是 EXPLAIN?

EXPLAIN 关键字可以放在 SELECTDELETEINSERTREPLACE 或 UPDATE 语句之前,MySQL 会返回该语句的执行计划,而不是真正执行它。

执行计划揭示了 MySQL 优化器决定如何访问表、使用哪些索引、表之间的连接方式等信息。

基本语法:

EXPLAIN your_sql_statement;
-- 例如
EXPLAIN SELECT * FROM users WHERE name = 'John';

在 MySQL 8.0 之后,推荐使用 EXPLAIN FORMAT=TRADITIONAL(默认格式),或者更详细的 EXPLAIN ANALYZE(MySQL 8.0.18+ 引入,会实际执行查询并给出更精确的分析)。

二、EXPLAIN 输出列详解

执行 EXPLAIN 后,你会得到一个包含多列的结果集。以下是这些列的含义,其中前几列(type, key, rows, Extra)最为重要

列名描述重要性
id查询中每个 SELECT 子句的唯一标识符。如果相同,则按顺序执行;如果不同,id 越大优先级越高(先执行)。
select_type查询的类型,如 SIMPLE, PRIMARY, SUBQUERY, DERIVED 等。
table正在访问的表名。
partitions匹配的分区,非分区表则为 NULL。
type连接类型 或 访问类型。这是衡量查询性能的最关键指标之一。
possible_keys查询中可能用到的索引。
key查询中实际决定使用的索引。为 NULL 则表示未使用索引。
key_len使用的索引键的长度。可用于判断是否充分利用了复合索引。
ref显示索引的哪一列被使用了,通常是一个常量(const)或另一个表的列名。
rowsMySQL 估计为了找到所需的行而需要读取的行数。这个值越小越好。
filtered表示存储引擎返回的数据在服务器层过滤后,剩余多少比例满足查询条件。理想是 100。
Extra包含不适合在其他列显示的额外信息,非常多的重要信息在这里。

三、核心列深度解析

1.type(访问类型)

性能从最优到最差排序如下:

system > const > eq_ref > ref > range > index > ALL

system:表只有一行记录(等于系统表),是 const 类型的特例。

const:通过索引一次就找到了,用于比较 主键索引 或 唯一索引 与常数值。速度极快。

EXPLAIN SELECT * FROM users WHERE id = 1;
-- `id` 是主键

eq_ref:在连接查询时,使用 主键 或 唯一非空索引 进行关联。对于来自前表的每一行,从本表中只返回一行。这是除了 system 和 const 之外最好的连接类型。

EXPLAIN SELECT * FROM users u 
JOIN orders o ON u.id = o.user_id;
-- `o.user_id` 是 `users` 表的主键 `id` 的外键,并且是唯一索引

ref:使用 非唯一性索引 进行扫描,返回匹配某个单独值的所有行。

EXPLAIN SELECT * FROM users WHERE name = 'John';
-- `name` 字段上有一个普通索引(非唯一)

range:只检索给定范围的行,使用一个索引来选择行。关键运算符是 BETWEEN><IN 等。

EXPLAIN SELECT * FROM users WHERE id > 10;
EXPLAIN SELECT * FROM users WHERE id IN (1, 2, 3);

index全索引扫描。遍历整个索引树来查找数据,比 ALL 快一点,因为索引文件通常比数据文件小。

EXPLAIN SELECT id FROM users;
-- 查询的列 `id` 正好是索引的一部分,直接从索引中读取,无需回表

ALL全表扫描。性能最差,意味着 MySQL 会遍历整张表来找到匹配的行。必须优化

2.rows(预估行数)

这不是查询结果的行数,而是 MySQL 为了找到目标记录,预估需要扫描多少行。这是一个基于统计信息的预估值。这个值越小越好,说明查询效率高。

3.Extra(额外信息)

这里包含大量细节,是判断查询质量的另一个关键。

  • Using index覆盖索引。查询的列都包含在索引中,无需回表查询数据行。性能极佳。
-- 假设在 `name` 和 `age` 上有一个复合索引 (name, age)
EXPLAIN SELECT name, age FROM users WHERE name = 'John';
  • Using where:表示在存储引擎返回行后,MySQL 服务器层再次进行了过滤。如果 type 是 ALL 或 index,并且出现 Using where,通常意味着性能不佳。
  • Using temporary:MySQL 需要创建一张临时表来处理查询。常见于 GROUP BY 和 ORDER BY 的子句涉及不同列时。需要优化
  • Using filesort:MySQL 无法使用索引对结果进行排序,需要额外的排序步骤。如果数据量大,会非常消耗资源。需要优化
  • Using join buffer:表示连接查询时,没有使用索引,需要用到连接缓冲区。通常意味着连接字段上没有索引。

四、实战分析示例

假设我们有两张表:

  • users 表
    • id (主键)
    • name (有普通索引)
  • email
    • orders 表
    • id (主键)
    • user_id (外键,关联 users.id,有索引)
  • amount

查询1:简单的等值查询

EXPLAIN SELECT * FROM users WHERE name = 'Alice';

可能的结果分析:

  • typeref (使用了非唯一索引)
  • keyname (实际使用了 name 索引)
  • rows: 1 (预估扫描1行)
  • Extra: (空,或者 Using index 如果查询的列都被索引覆盖)

结论: 这是一个高效的查询。

查询2:连接查询

EXPLAIN SELECT u.name, o.amount 
FROM users u 
JOIN orders o ON u.id = o.user_id 
WHERE u.name = 'Bob';

可能的结果分析(对于 orders 表这一行):

  • typeref (使用 user_id 索引来关联)
  • keyuser_id
  • rows: 5 (预估每个用户平均有5个订单)
  • Extra: (空)

结论: 连接效率很高,因为双方都使用了索引。

查询3:性能不佳的查询

EXPLAIN SELECT * FROM users WHERE email = 'alice@example.com' ORDER BY name;

可能的结果分析:

  • typeALL (全表扫描,因为 email 字段没有索引)
  • keyNULL
  • rows: 10000 (表中有1万行数据)
  • ExtraUsing filesort (在内存或磁盘上进行排序)

结论: 这是一个灾难性的查询。它进行了全表扫描,并且还有一个昂贵的文件排序。
优化建议:

  • 为 email 字段添加索引。
  • 如果经常需要按 name 排序,可以考虑建立 (email, name) 的复合索引,这样可以利用索引来查找和排序。

五、进阶工具:EXPLAIN ANALYZE (MySQL 8.0.18+)

EXPLAIN ANALYZE 会实际执行查询,并提供一个更详细的、包含实际执行时间的分析报告。

EXPLAIN ANALYZE SELECT * FROM users WHERE name = 'John';

输出格式类似于:

-> Index lookup on users using idx_name (name='John')  (cost=0.35 rows=1) (actual time=0.025..0.027 rows=1 loops=1)

它提供了:

  • 实际执行时间 (actual time)。
  • 实际返回行数 (rows)。
  • 执行循环次数 (loops)。
  • 预估成本 (cost)。

这比传统的 EXPLAIN 提供了更精确的性能视图。

总结

检查点目标
type 列至少达到 range 级别,最好能到 ref。避免 ALL
key 列确保查询实际使用了合适的索引,不为 NULL
rows 列预估扫描行数尽可能小。
Extra 列追求出现 Using index。警惕 Using temporary 和 Using filesort

熟练掌握 EXPLAIN 是每个后端开发者和 DBA 的必备技能,它能帮助你从“猜测”优化变为“数据驱动”的优化。

到此这篇关于MySQL EXPLAIN 详解与优化指南的文章就介绍到这了,更多相关mysql explain内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • Navicat配置mysql数据库用户权限问题

    Navicat配置mysql数据库用户权限问题

    这篇文章主要介绍了Navicat配置mysql数据库用户权限问题,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2023-03-03
  • MySQL在读已提交和可重复读这两个不同事务隔离级别下幻读的区别及说明

    MySQL在读已提交和可重复读这两个不同事务隔离级别下幻读的区别及说明

    这篇文章主要介绍了MySQL在读已提交和可重复读这两个不同事务隔离级别下幻读的区别及说明,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教
    2025-06-06
  • Window环境下MySQL UDF提权

    Window环境下MySQL UDF提权

    本文章仅记录某次内网渗透过程中遇到的MySQL 采用UDF提权等方式进行获取权限,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧<BR>
    2023-03-03
  • MySQL权限变更何时生效

    MySQL权限变更何时生效

    本文为大家讲述了对三种级别权限的变更后,使其生效的方法,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪<BR>
    2023-10-10
  • MySQL安装与配置:如何重置MySQL登录密码(windows环境)

    MySQL安装与配置:如何重置MySQL登录密码(windows环境)

    这篇文章主要介绍了MySQL安装与配置:如何重置MySQL登录密码(windows环境),具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教
    2023-12-12
  • Mysql 1864 主从错误解决方法

    Mysql 1864 主从错误解决方法

    本文给大家带来了Mysql 1864 主从错误解决方法,本文介绍的非常详细,具有参考借鉴价值,需要的朋友可以参考下
    2016-08-08
  • Windows下MySQL服务启动常见的两种方式(适配5.7和8.0)

    Windows下MySQL服务启动常见的两种方式(适配5.7和8.0)

    本文主要介绍了Windows下MySQL服务启动常见的两种方式(适配5.7和8.0),文中通过图文介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2024-07-07
  • MySQL中安装样本数据库Sakila过程分享

    MySQL中安装样本数据库Sakila过程分享

    这篇文章主要介绍了MySQL中安装样本数据库Sakila过程分享,Sakila数据库主要用来做一些基本的操作以及压力测试等,需要的朋友可以参考下
    2014-10-10
  • mysql使用instr达到in(字符串)的效果

    mysql使用instr达到in(字符串)的效果

    本文主要介绍了mysql使用instr达到in(字符串)的效果,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2022-04-04
  • mysql like查询字符串示例语句

    mysql like查询字符串示例语句

    在mysql中如果我们要模糊查询数据我们可以使用like带%%号来实现查询,下面我来简单的介绍一下关于mysql like使用方法
    2013-10-10

最新评论