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内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • MySQL约束和表的复杂查询操作大全

    MySQL约束和表的复杂查询操作大全

    约束是关系型数据库的一个重要功能, 添加到库中的数据需要保证其的正确性; 约束, 就是让数据库帮助程序员更好的检查数据是否正确.,这篇文章主要介绍了MySQL约束和表的复杂查询操作,需要的朋友可以参考下
    2022-11-11
  • MySQL中Distinct和Group By语句的基本使用教程

    MySQL中Distinct和Group By语句的基本使用教程

    这篇文章主要介绍了MySQL中Distinct和Group By语句的基本使用教程,这里主要是针对查询结果去重的用法,需要的朋友可以参考下
    2015-12-12
  • Linux系统中MySQL的常用操作命令

    Linux系统中MySQL的常用操作命令

    本文给大家汇总介绍了下载Linux系统中操作mysql的一些常用的命令,非常实用,有需要的小伙伴可以参考下
    2018-02-02
  • mysql 5.5 安装配置方法图文教程

    mysql 5.5 安装配置方法图文教程

    这篇文章主要为大家分享了mysql 5.5安装配置方法图文教程,感兴趣的朋友可以参考一下
    2016-11-11
  • MySQL中length()、char_length()的区别

    MySQL中length()、char_length()的区别

    在MySQL中length(str)、char_length(str)都属于判断长度的内置函数,本文主要介绍了MySQL中length()、char_length()的区别,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2023-05-05
  • MySQL8.0.20单机多实例部署步骤

    MySQL8.0.20单机多实例部署步骤

    本文主要介绍了MySQL8.0.20单机多实例部署步骤,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2022-05-05
  • Docker MySQL启动问题及解决过程

    Docker MySQL启动问题及解决过程

    Docker MySQL启动失败多因权限限制导致无法写入/tmp和/var/run/mysqld目录,推荐使用tmpfs挂载卷解决,同时需检查SELinux和数据目录权限,避免使用特权模式
    2025-09-09
  • mysql 大表批量删除大量数据的实现方法

    mysql 大表批量删除大量数据的实现方法

    这篇文章主要介绍了mysql 大表批量删除大量数据的实现方法,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2021-02-02
  • MySQL连接异常报10061错误问题解决

    MySQL连接异常报10061错误问题解决

    这篇文章主要介绍了MySQL连接异常报10061错误问题解决,本篇文章通过简要的案例,讲解了该项技术的了解与使用,以下就是详细内容,需要的朋友可以参考下
    2021-08-08
  • MySQL如何为字段添加默认时间浅析

    MySQL如何为字段添加默认时间浅析

    这篇文章主要给大家介绍了关于MySQL如何为字段添加默认时间的相关资料,文中通过示例代码介绍的非常详细,对大家的学习或者使用MySQL具有一定的参考学习价值,需要的朋友们下面来一起学习学习吧
    2019-10-10

最新评论