mysql 的 explain

MySQL EXPLAIN 深度解析与优化

一、MySQL EXPLAIN 是什么?

EXPLAIN 是 MySQL 中用于分析 SQL 执行计划的核心命令,它能告诉你 MySQL 优化器会如何执行这条 SQL(比如用什么索引、扫描多少行、连接方式等),是优化慢 SQL 的必备工具。

可以把它理解为:你写了一条 SQL 想让 MySQL 执行,EXPLAIN 会提前告诉你 MySQL 的"执行思路"------ 走哪条路、做哪些操作、效率怎么样,帮你找到 SQL 里的性能瓶颈。

二、基本用法

1. 语法
sql 复制代码
EXPLAIN + 你的SQL语句;
-- 示例
EXPLAIN SELECT * FROM user WHERE id = 1;

如果想查看更详细的执行计划(比如执行时的成本、临时表等),可以用:

sql 复制代码
EXPLAIN ANALYZE SELECT * FROM user WHERE id = 1; -- MySQL 8.0 及以上支持
2. 输出字段说明

执行 EXPLAIN 后会返回一个结果集,核心字段如下(新手先掌握这 8 个核心字段即可):

字段 核心含义
id SQL 执行的顺序(子查询/联表时会有多个 id,数字越大越先执行)
select_type 查询类型(比如简单查询、子查询、联表查询、衍生表等)
table 本次执行涉及的表名
type 访问类型(核心!判断性能的关键,从差到好:ALL < index < range < ref < eq_ref < const/system)
possible_keys MySQL 可能会选择的索引(候选索引)
key MySQL 实际使用的索引(如果为 NULL,说明没用到索引)
rows MySQL 预估要扫描的行数(数值越小越好)
Extra 额外信息(比如 Using index 走覆盖索引、Using where 过滤条件、Using filesort 排序等)

三、核心字段详解(新手重点)

1. type(访问类型)

这是 EXPLAIN最重要的字段,直接反映 SQL 的性能层级,常见值从差到优排序:

  • ALL :全表扫描(最差!会遍历整个表),比如 SELECT * FROM user; 且无任何条件。
  • index:全索引扫描(比 ALL 好一点,但仍扫描整个索引),比如查询的字段都在索引里,但无过滤条件。
  • range :索引范围扫描(比如用 >、<、BETWEEN、IN 等),比如 SELECT * FROM user WHERE id BETWEEN 1 AND 10;
  • ref :非唯一索引扫描(匹配多行),比如 SELECT * FROM user WHERE name = '张三';(name 是普通索引)。
  • eq_ref :唯一索引扫描(匹配一行),比如联表查询时用主键/唯一索引关联,SELECT * FROM user u JOIN order o ON u.id = o.user_id;
  • const/system :查询结果能确定为一行(最优),比如用主键查询 SELECT * FROM user WHERE id = 1;
2. key(实际使用的索引)
  • 如果 keyNULL,说明 MySQL 没用到索引,大概率是 SQL 写得有问题(比如用了函数操作索引字段、条件不匹配索引等)。
  • 示例:如果 user 表的 id 是主键(默认索引),执行 EXPLAIN SELECT * FROM user WHERE id = 1;key 列会显示 PRIMARY(主键索引名)。
3. Extra(关键提示)
  • Using index:走了"覆盖索引"(查询的字段都在索引里,无需回表查数据),性能极佳。

示例:user 表有索引 idx_name_age (name, age),执行 EXPLAIN SELECT name, age FROM user WHERE name = '张三';,Extra 会显示 Using index

  • Using where:MySQL 会先扫描数据,再用 WHERE 条件过滤(如果同时有 Using index,说明先走索引再过滤)。
  • Using filesort :MySQL 需额外做排序(不是用索引排序),性能差,比如 SELECT * FROM user ORDER BY name; 但 name 无索引。
  • Using temporary:MySQL 需创建临时表(比如 GROUP BY 没用到索引),性能差,要优化。

四、实战示例

假设有一张 user 表,结构如下:

go 复制代码
CREATE TABLE `user` (
  `id` int PRIMARY KEY AUTO_INCREMENT,
  `name` varchar(20) NOT NULL,
  `age` int,
  `gender` tinyint,
  INDEX `idx_name` (`name`) -- 普通索引
);
示例 1:全表扫描(差)
sql 复制代码
EXPLAIN SELECT * FROM user WHERE age = 20;
  • type:ALL(全表扫描)
  • key:NULL(没用到索引)
  • Extra:Using where(扫描后过滤)
  • 优化:给 age 加索引 ALTER TABLE user ADD INDEX idx_age (age);
示例 2:使用索引(好)
sql 复制代码
EXPLAIN SELECT * FROM user WHERE name = '张三';
  • type:ref(非唯一索引扫描)
  • key:idx_name(用到了 name 的索引)
  • rows:预估扫描行数(比如 10 行,远小于全表行数)。
示例 3:覆盖索引(优)
sql 复制代码
EXPLAIN SELECT name FROM user WHERE name = '张三';
  • type:ref
  • key:idx_name
  • Extra:Using index(覆盖索引,无需回表)。

五、使用注意事项

  1. EXPLAINrows 是 MySQL 预估的扫描行数,不是实际行数,但能反映性能趋势(数值越小越好)。
  2. EXPLAIN 只分析执行计划,不会实际执行 SQL(除非用 EXPLAIN ANALYZE),所以可以放心在生产环境使用。
  3. 即使 possible_keys 有值,key 也可能为 NULL ------ 说明 MySQL 认为走索引不如全表扫描快(比如表数据量极小)。

总结

  1. EXPLAIN 是分析 SQL 执行计划的核心工具,重点看 type(访问类型)、key(实际索引)、Extra(额外提示)三个字段。
  2. 优化目标:尽量让 type 达到 range 及以上,key 不为 NULL,避免 Extra 出现 Using filesort/Using temporary
  3. 最理想的执行计划:type 为 const/system + key 有值 + Extra 显示 Using index
相关推荐
2401_895521348 小时前
SpringBoot Maven快速上手
spring boot·后端·maven
disgare8 小时前
关于 spring 工程中添加 traceID 实践
java·后端·spring
ictI CABL8 小时前
Spring Boot与MyBatis
spring boot·后端·mybatis
小江的记录本10 小时前
【Linux】《Linux常用命令汇总表》
linux·运维·服务器·前端·windows·后端·macos
yhole13 小时前
springboot三层架构详细讲解
spring boot·后端·架构
香香甜甜的辣椒炒肉13 小时前
Spring(1)基本概念+开发的基本步骤
java·后端·spring
白毛大侠14 小时前
Go Goroutine 与用户态是进程级
开发语言·后端·golang
ForteScarlet14 小时前
从 Kotlin 编译器 API 的变化开始: 2.3.20
android·开发语言·后端·ios·开源·kotlin
大阿明14 小时前
SpringBoot - Cookie & Session 用户登录及登录状态保持功能实现
java·spring boot·后端
Binary-Jeff14 小时前
Spring 创建 Bean 的关键流程
java·开发语言·前端·spring boot·后端·spring·学习方法