当前位置: 首页 > web >正文

MySQL EXPLAIN 解读

        在 MySQL 里,EXPLAIN是一个很实用的语句,主要用于分析 SQL 查询的执行计划。通过它,你能够了解到 MySQL 是怎样处理查询语句的,这有助于优化查询性能、分析索引使用情况。

一、基本用法

EXPLAIN SELECT * FROM users WHERE age > 25;

        支持SELECTINSERTUPDATEDELETE等语句;MySQL 8.0+ 支持EXPLAIN ANALYZE获取更详细执行数据。

示例:

二、关键字段解析

1、id

        该语句的唯一标识。如果explain的结果包括多个id值,则数字越大越先执行;而对于相同id的行,则表示从上往下依次执行。

2、select_type

查询类型:

simple:简单select(不使用union或子查询)。

primary:最外面的select。

union:union中的第二个或后面的select语句。

dependent union:union中的第二个或后面的select语句,取决于外面的查询。

union result:union的结果。

subquery:子查询中的第一个select。

dependent subquery:子查询中的第一个select,取决于外面的查询。

derived:导出表的select(from子句的子查询)。

3、table

当前的表

4、type

type指查询使用了哪种类型,反映了 MySQL 如何查找表中的行。连接类型的效率从高到低排序如下:

4.1. system:表中只有一行数据(系统表),这是效率最高的连接类型。

4.2. const:通过索引一次就能找到数据,通常用于主键或唯一索引的等值查询。

EXPLAIN SELECT * FROM users WHERE id = 1;+----+-------------+-------+-------+---------------+---------+---------+-------+------+-------+
| id | select_type | table | type  | possible_keys | key     | key_len | ref   | rows | Extra |
+----+-------------+-------+-------+---------------+---------+---------+-------+------+-------+
| 1  | SIMPLE      | users | const | PRIMARY       | PRIMARY | 4       | const | 1    |       |
+----+-------------+-------+-------+---------------+---------+---------+-------+------+-------+

4.3. eq_ref:对于每个索引键,表中只有一条记录与之匹配,常见于主键或唯一索引的关联查询。

-- 假设orders表的user_id字段关联users表的主键
EXPLAIN SELECT * FROM users 
JOIN orders ON users.id = orders.user_id 
WHERE users.id = 1;
+----+-------------+-------+--------+---------------+---------+---------+----------------+------+-------+
| id | select_type | table | type   | possible_keys | key     | key_len | ref            | rows | Extra |
+----+-------------+-------+--------+---------------+---------+---------+----------------+------+-------+
| 1  | SIMPLE      | users | const  | PRIMARY       | PRIMARY | 4       | const          | 1    |       |
| 1  | SIMPLE      | orders| eq_ref | user_id       | user_id | 4       | test.users.id  | 1    |       |
+----+-------------+-------+--------+---------------+---------+---------+----------------+------+-------+

4.4. ref:使用非唯一索引或唯一索引的前缀进行查找,返回匹配某个值的所有行。

-- 假设name字段有普通索引
EXPLAIN SELECT * FROM users WHERE name = 'Alice';
+----+-------------+-------+------+---------------+------+---------+-------+------+-------+
| id | select_type | table | type | possible_keys | key  | key_len | ref   | rows | Extra |
+----+-------------+-------+------+---------------+------+---------+-------+------+-------+
| 1  | SIMPLE      | users | ref  | idx_name      | idx_name | 767     | const | 10   |       |
+----+-------------+-------+------+---------------+------+---------+-------+------+-------+

4.5. range:只检索给定范围的行,使用一个索引来选择行,常见于 WHERE 子句中的 ><BETWEEN 等操作。

EXPLAIN SELECT * FROM products WHERE price BETWEEN 100 AND 200;+----+-------------+----------+-------+---------------+-----------+---------+------+------+-------------+
| id | select_type | table    | type  | possible_keys | key       | key_len | ref  | rows | Extra       |
+----+-------------+----------+-------+---------------+-----------+---------+------+------+-------------+
| 1  | SIMPLE      | products | range | idx_price     | idx_price | 8       | NULL | 500  | Using where |
+----+-------------+----------+-------+---------------+-----------+---------+------+------+-------------+

4.6. index:全索引扫描,与 ALL 类似,但只扫描索引树,通常比 ALL 快,因为索引文件通常比数据文件小。

-- 假设name字段有索引,查询只需要name字段
EXPLAIN SELECT name FROM users;
+----+-------------+-------+-------+---------------+------+---------+------+------+-------------+
| id | select_type | table | type  | possible_keys | key  | key_len | ref  | rows | Extra       |
+----+-------------+-------+-------+---------------+------+---------+------+------+-------------+
| 1  | SIMPLE      | users | index | NULL          | idx_name | 767     | NULL | 1000 | Using index |
+----+-------------+-------+-------+---------------+------+---------+------+------+-------------+

4.7. ALL:全表扫描,MySQL 必须遍历全表来找到匹配的行,这是效率最低的连接类型。

EXPLAIN SELECT * FROM users WHERE age > 30;
+----+-------------+-------+------+---------------+------+---------+------+------+-------------+
| id | select_type | table | type | possible_keys | key  | key_len | ref  | rows | Extra       |
+----+-------------+-------+------+---------------+------+---------+------+------+-------------+
| 1  | SIMPLE      | users | ALL  | NULL          | NULL | NULL    | NULL | 1000 | Using where |
+----+-------------+-------+------+---------------+------+---------+------+------+-------------+

5、possible_keys

        显示 MySQL 在执行查询时,理论上可能使用的索引。这些索引基于查询条件(如 WHERE 子句、JOIN 条件)中的字段。注意:该字段仅列出可能的索引,不代表实际使用。

6、key

        显示 MySQL 在实际执行查询时选择使用的索引。如果为 NULL,表示未使用任何索引(可能是全表扫描)。

MySQL 会根据索引选择性、统计信息和执行成本,从 possible_keys 中选择最优索引。

7、key_len

        显示 MySQL 在查询中使用的索引字段的总长度,包括可能的 NULL 值标记位和字符集占用的字节数。

8、ref

示了在执行查询时,哪些值被用于与索引进行匹配。

这些值可以是:常量(如 const)其他表的列(如 table_name.column_name)表达式

当查询条件为常量(如 WHERE id = 1)且使用主键或唯一索引时,ref 显示为 const

EXPLAIN SELECT * FROM users WHERE id = 100;
+----+-------------+-------+-------+---------------+---------+---------+-------+------+-------+
| id | select_type | table | type  | possible_keys | key     | key_len | ref   | rows | Extra |
+----+-------------+-------+-------+---------------+---------+---------+-------+------+-------+
| 1  | SIMPLE      | users | const | PRIMARY       | PRIMARY | 4       | const | 1    |       |
+----+-------------+-------+-------+---------------+---------+---------+-------+------+-------+

 在 JOIN 查询中,当使用一个表的列与另一个表的索引进行匹配时,ref 显示为关联表的列名。

EXPLAIN SELECT * 
FROM orders 
JOIN users ON orders.user_id = users.id 
WHERE users.id = 100;
+----+-------------+--------+--------+---------------+---------+---------+----------------+------+-------+
| id | select_type | table  | type   | possible_keys | key     | key_len | ref            | rows | Extra |
+----+-------------+--------+--------+---------------+---------+---------+----------------+------+-------+
| 1  | SIMPLE      | users  | const  | PRIMARY       | PRIMARY | 4       | const          | 1    |       |
| 1  | SIMPLE      | orders | ref    | user_id       | user_id | 4       | test.users.id  | 5    |       |
+----+-------------+--------+--------+---------------+---------+---------+----------------+------+-------+

当查询条件使用函数或表达式时,ref 显示为 func

EXPLAIN SELECT * FROM users WHERE YEAR(created_at) = 2023;
+----+-------------+-------+------+------------------+------------------+---------+------+------+-------------+
| id | select_type | table | type | possible_keys    | key              | key_len | ref  | rows | Extra       |
+----+-------------+-------+------+------------------+------------------+---------+------+------+-------------+
| 1  | SIMPLE      | users | ref  | idx_created_at   | idx_created_at   | 5       | func | 100  | Using where |
+----+-------------+-------+------+------------------+------------------+---------+------+------+-------------+

9、rows

        是 MySQL 优化器根据统计信息估算的,为了执行查询而需要扫描的行数。这个值是一个估算值,并非精确值。

10、filtered

表示 MySQL 优化器估算的,在扫描了 rows 行数据后,最终满足 WHERE 子句条件的行的百分比。

        取值范围:0.00%(无匹配)到 100.00%(全部匹配)

例:

rows = 1:通过主键精确匹配,仅需扫描 1 行。

filtered = 100.00%:主键查询精确匹配,所有扫描行均满足条件。

EXPLAIN SELECT * FROM users WHERE id = 100;
+----+-------------+-------+-------+---------------+---------+---------+-------+------+-------+
| id | select_type | table | type  | possible_keys | key     | key_len | ref   | rows | Extra |
+----+-------------+-------+-------+---------------+---------+---------+-------+------+-------+
| 1  | SIMPLE      | users | const | PRIMARY       | PRIMARY | 4       | const | 1    |       |
+----+-------------+-------+-------+---------------+---------+---------+-------+------+-------+

11、Extra

  Extra 是一个非常关键的字段,它提供了关于 MySQL 执行查询时的额外细节信息,补充了其他字段(如 keyrows 等)未涵盖的执行逻辑,是判断查询性能瓶颈的重要依据。

  Extra 字段会显示 MySQL 如何处理查询的具体方式,例如是否使用了索引覆盖、是否需要临时表、是否需要额外排序、是否进行了全表扫描等。这些信息能直接反映查询的效率高低,帮助我们优化 SQL(比如调整索引、改写查询逻辑)。

理想情况(高效执行)

Using index
表示查询使用了覆盖索引(Covering Index),即查询所需的所有字段(SELECT 后的列、WHERE 条件列等)都包含在某个索引中,MySQL 无需回表查询数据行,直接通过索引即可获取结果。

Using where; Using index
表示查询既使用了索引(Using index),又通过索引过滤了数据(Using where),但仍无需回表。

Using index condition
表示使用了索引条件下推(Index Condition Pushdown, ICP) 优化。MySQL 会在存储引擎层(而非服务器层)就用索引过滤部分数据,减少回表次数。

Range
表示查询使用了索引的范围扫描(如 WHERE id BETWEEN 1 AND 100 或 WHERE name LIKE '张%'),仅扫描索引中符合范围的部分,而非全索引扫描。

需要优化的情况(低效执行)

Using filesort
表示 MySQL 需要对结果进行额外的排序操作(排序未通过索引完成)。

Using temporary
表示 MySQL 需要创建临时表来存储中间结果(通常用于 GROUP BYDISTINCT 或多表连接时)。

Using where
单独出现时,表示 MySQL 使用了索引查找数据,但索引无法直接过滤所有条件,需要在获取数据行后,再通过 WHERE 条件进一步过滤(可能需要回表)。

Using join buffer
表示多表连接时,MySQL 未使用索引连接,而是使用了连接缓冲区(Join Buffer)存储中间结果。

Using full scan
表示查询进行了全表扫描(Full Table Scan),未使用任何索引。

Impossible WHERE
表示 WHERE 条件永远为 FALSE,MySQL 无需执行任何查询(直接返回空结果)。

Range checked for each record (index map: N)
表示 MySQL 无法确定使用哪个索引,只能对前一张表的每一行,都尝试检查是否有合适的索引可用(通常发生在多表连接且索引不明确时)。

http://www.xdnf.cn/news/15944.html

相关文章:

  • DAY 20 奇异值分解(SVD)
  • ant+Jmeter+jenkins接口自动化,如何实现把执行失败的接口信息单独发邮件?
  • leetcode丑数II计算第n个丑数
  • zabbix服务器告警处理
  • 【milvus检索】milvus检索召回率
  • pages.json页面路由中,globalStyle的各个属性
  • 社交圈子系统开源社交源码 / 小程序+H5+APP 多端互通的底层技术分析
  • Ubuntu 24.04 设置静态 IP 的方法
  • 对LLM某一层进行优化:通过眼动数据发现中间层注重语句内在含义,进而对中间层参数优化
  • pthread_detach与pthread_join区别及使用场景
  • 408考研逐题详解:2010年第35题——RIP协议
  • BST(二叉搜索树)的笔试大题(C语言)
  • AG32:解锁MCU+FPGA应用新姿势,功能与实战全解析
  • SQL中的EXPLAIN命令详解
  • 【Linux】权限详解 权限本质、权限属性、su、sudo提权、chmod\chown\chgrp、文件类别
  • Qt 应用程序入口代码分析
  • HarmonyOS 启动提速秘籍:懒加载全链路实战解析
  • mysql第三次作业
  • 什么是的优先级反转(Priority Inversion) 和 优先级继承(Priority Inheritance)?
  • Syncthing实时共享同步数据 服务器数据备份软件(linux、windows)
  • 《程序员修炼之道》第一二章读书笔记
  • 【ChatOpenAI】常用方法详解
  • Helm常用命令大全(2025最新版)
  • 二分查找-69.x的平方根-力扣(LeetCode)
  • 大语言模型置信度增强实战指南
  • (LeetCode 每日一题) 1233. 删除子文件夹 (排序)
  • 统计学习方法
  • 堆堆堆,咕咕咕
  • python的多线程无法并行只能并发,why?
  • GA-BP遗传算法优化BP神经网络数据生成,采用SVM分类模型评估