当前位置: 代码网 > it编程>数据库>Mysql > MySQL EXPLAIN用法实例深度详解

MySQL EXPLAIN用法实例深度详解

2026年04月07日 Mysql 我要评论
一、什么是 explainexplain 是 mysql 提供的一个用于分析 sql 语句执行计划的强大工具。通过它,我们可以了解 mysql 查询优化器是如何执行 sql 语句的,包括表的读取顺序、

一、什么是 explain

explain 是 mysql 提供的一个用于分析 sql 语句执行计划的强大工具。通过它,我们可以了解 mysql 查询优化器是如何执行 sql 语句的,包括表的读取顺序、索引使用情况、扫描行数等关键信息,从而帮助我们定位和优化性能瓶颈。

版本说明:本文基于 mysql 5.7+ 和 8.0+ 版本。explain analyze 和 hash join 特性需要 mysql 8.0.18+ 和 8.0.20+。

二、基本语法

2.1 标准用法

explain select * from table_name where condition;

2.2 支持的语句类型

explain 支持以下语句:

  • select
  • delete
  • insert
  • replace
  • update

2.3 mysql 8.0+ 新增用法

-- 实际执行并分析耗时(mysql 8.0.18+)
explain analyze select * from users where age = 25;
-- json 格式输出(包含成本模型数据)
explain format=json select * from users where age = 25;

三、explain 输出字段详解

执行 explain 后,mysql 会返回一个结果集,包含以下列:

字段

含义

id

查询标识符,表示执行顺序

select_type

查询类型(simple、primary、subquery 等)

table

访问的表名

partitions

匹配的分区(mysql 5.7+)

type

访问类型(all、index、range、ref、eq_ref 等)

possible_keys

可能使用的索引

key

实际使用的索引

key_len

使用的索引长度

ref

与索引比较的列或常量

rows

估算需要扫描的行数

filtered

按条件过滤后剩余行的百分比(mysql 5.7+)

extra

额外信息(非常重要)

四、核心字段深度解析

4.1 id 列 - 执行顺序标识

规则

  • id 相同:从上往下顺序执行
  • id 不同:id 值越大,优先级越高,越先执行
  • id 为 null:最后执行(通常是 union 结果合并)
-- 示例:子查询
explain select * from test1 where id in (select id from test2);
-- 结果中 id=2 的子查询会先执行,id=1 的主查询后执行

4.2 select_type 列 - 查询类型

类型

说明

simple

简单查询,不包含子查询或 union

primary

最外层查询

subquery

select 或 where 中的子查询

derived

from 中的子查询(派生表)

union

union 中的第二个及后续查询

union result

union 结果合并

4.3 type 列 - 访问类型(性能关键)

性能从优到劣排序

类型

说明

system

不进行磁盘io,查询系统表,仅仅返回一条数据

const

通过主键或唯一索引一次就找到

eq_ref

连接查询中,被驱动表使用主键/唯一索引等值匹配

ref

使用普通索引等值匹配

range

索引范围扫描(between、in、>、< 等)

index

遍历整颗索引树,比all快一些,因为索引文件要比数据文件小

all

全表扫描

优化建议:至少达到 range 级别,最好达到 refeq_ref

4.4 extra 列 - 额外信息

这是最重要的优化线索列:

含义

优化建议

using index

使用覆盖索引

理想状态,无需回表

using where

使用 where 过滤(全表扫描或者在查找使用索引的情况下,但是还有查询条件不在索引字段当中)

正常情况

using filesort

使用外部排序(无法利用索引排序)

 需要优化,考虑添加索引

using temporary

使用临时表来存储结果集,常见于排序和分组查询

常见于 group by / order by,需优化

using join buffer

使用连接缓存

连接条件未使用索引

impossible where

where 条件永远为 false

检查逻辑

select tables optimized away

优化器确定最多返回一行

无需优化

五、实战案例

5.1 单表查询分析

-- 表结构:users(id, age, score, name, address)
-- 索引:idx_age_score_name(age, score, name)
explain select * from users where age = 25;

结果分析

+----+-------------+-------+------------+------+---------------------+---------------------+---------+-------+------+----------+-------------+
| id | select_type | table | partitions | type | possible_keys       | key                 | key_len | ref   | rows | filtered | extra       |
+----+-------------+-------+------------+------+---------------------+---------------------+---------+-------+------+----------+-------------+
|  1 | simple      | users | null       | ref  | idx_age_score_name  | idx_age_score_name  | 5       | const |   12 |   100.00 | using index |
+----+-------------+-------+------------+------+---------------------+---------------------+---------+-------+------+----------+-------------+

解读

  • type=ref:使用普通索引等值匹配
  • key=idx_age_score_name:实际使用了联合索引
  • extra=using index:覆盖索引,无需回表查询
  • rows=12:只需扫描 12 行

5.2 连接查询分析

explain select * from test1 t1 
inner join test2 t2 on t1.id = t2.id;

关键观察点

  • 查看哪个表是驱动表(通常 rows 小的作为驱动表更优)
  • 被驱动表的 type 应该为 eq_ref(使用主键/唯一索引)

5.3 使用 explain analyze(mysql 8.0.18+)

explain analyze select * from users where age = 25\g

输出示例

*************************** 1. row ***************************
explain: -> covering index lookup on users using idx_age_score_name (age=25)
(cost=1.52 rows=12) (actual time=0.0272..0.0344 rows=12 loops=1)

优势

  • 显示实际执行时间(actual time)
  • 显示实际返回行数(rows)
  • 比标准 explain 的估算数据更可靠

六、常见优化场景

6.1 避免全表扫描(type = all)

问题诊断

  • 查询条件列没有索引
  • 查询使用函数导致索引失效
  • 多表 join 驱动表选择不合理

优化方法

-- 错误:函数包装导致索引失效
select * from orders where year(order_date) = 2023;
-- 正确:改写为范围查询
select * from orders 
where order_date >= '2023-01-01' and order_date < '2024-01-01';

6.2 消除文件排序(using filesort)

-- 添加合适的索引避免 filesort
create index idx_age_name on users(age, name);
-- 查询同时满足 where 和 order by
select * from users where age > 20 order by age, name;

6.3 利用覆盖索引

-- 索引:idx_age_name(age, name)
-- ✅ 覆盖索引查询(extra = using index)
explain select age, name from users where age = 25;
-- ❌ 非覆盖索引(需要回表查询)
explain select * from users where age = 25;

七、explain 的局限性

需要注意 explain 的以下限制:

  1. 不会告诉你关于触发器、存储过程的信息
  2. 不考虑各种 cache(查询缓存等)
  3. 不能显示 mysql 在执行查询时所作的优化工作
  4. 部分统计信息是估算的,并非精确值
  5. 标准 explain 不会真正执行 sql(除 explain analyze 外)

八、总结

检查项

优化目标

type

至少达到 range,最好 ref 或 eq_ref

key

确保实际使用了索引

rows

越小越好

extra

避免出现 using filesort、using temporary

覆盖索引

尽量让 extra 显示 using index

掌握 explain 的使用是 sql 性能优化的基础技能。通过分析执行计划,我们可以快速定位性能瓶颈,有针对性地进行索引优化和 sql 改写

到此这篇关于mysql explain用法的文章就介绍到这了,更多相关mysql explain用法内容请搜索代码网以前的文章或继续浏览下面的相关文章希望大家以后多多支持代码网!

(0)

相关文章:

版权声明:本文内容由互联网用户贡献,该文观点仅代表作者本人。本站仅提供信息存储服务,不拥有所有权,不承担相关法律责任。 如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至 2386932994@qq.com 举报,一经查实将立刻删除。

发表评论

验证码:
Copyright © 2017-2026  代码网 保留所有权利. 粤ICP备2024248653号
站长QQ:2386932994 | 联系邮箱:2386932994@qq.com