Mysql执行计划——解读Explain

本文深入解析MySQL执行计划,包括查看方法、字段含义及其优化策略。涵盖SELECT_TYPE、TYPE、POSSIBLE_KEYS等关键概念,帮助理解SQL执行效率。

mysql的执行计划再熟悉不过了,sql优化经常使用,但是里面很多字段都是知道个大概,没有很系统的学习过。今天就抽空整理一下这块的知识点。

如何查看执行计划


在要分析的sql之前加上 explain 关键字。
举个例子

explain 
select * from table

字段说明


id

普通的id字段,一般不用

select_type

查询类型

说明
SIMPLE单表查询,不包含任何子部分
PRIMARY如果包含复杂的子部分,最外层部分标记为PRIMARY
DERIVED在from后面的子查询,mysql会为子查询创建一个临时表,也叫派生表
SUBQUERY包含在select列表中的子查询
UNION在union语句中,第二个开始的表都会被标记为UNION
UNION RESULT用来从UNION的匿名临时表检索结果的select被标记为UNION RESULT

一般比较常用的是SIMPLE,PRIMARY,DERIVED。记住这三个,其他用的时候查资料就行。

table

当前sql访问的表名
当sql包含子查询时,table字段会标记为<derivedN> 这里的N是子查询对应id
举个例子

select count(1) from (select * from table) t

对应的执行计划应该是

idselect_typetable
1PRIMARY<derived2>
2DERIVEDtable

可以在从一列中从上往下观察 关联优化器 为查询选择的关联顺序。
举个例子

   explain 
   select film.file_id
   from film
   inner join film_actor using(film_id)
   inner join actor using(actor_id)

对应的执行计划是

idselect_typetable
1SIMPLEactor
2SIMPLEfilm_actor
3SIMPLEfilm
mysql的执行计划总是左侧深度树优先,我们可以根据这个原则从执行计划中解读出关联顺序。关联顺序与执行计划的关系如下图所示。
在这里插入图片描述

partitions

查询使用到表分区的分区名

type

访问类型,这个字段很重要。下面从差到优枚举一下。

说明
ALL全表扫描,mysql需要扫描整张表才能取到想要的数据
index按索引的顺序读取整个表的数据。
相比ALL,index的优点是避免排序。
出现index通常意味着若是按随机次序访问行,开销会非常大。
如果在EXtra列中看到"Using index",说明Mysql正在使用覆盖索引,
它只扫描索引的数据,不是按索引次序扫描的每一行(不回表)。
rang范围扫描是一个有限制的索引扫描。
它开始于索引的某一点,返回匹配的行。
rang比index好一些,因为它不需要全索引扫描
ref索引访问,返回所有匹配某个单个值的行。
它可能返回多行,所以它是查找和扫描的混合体。
出现在使用非唯一索引,或者唯一索引的非唯一前缀时。
eq_ref索引查找
和ref一样返回所有匹配某个单个值的行。区别是它只可能返回一行。
eq_ref可以在使用主键或者唯一键执行sql的时候看到。
const当Mysql能将某部分查询语句转化成一个常量时,它就会使用const访问类型。
简单来说就是当查询最多只有一个匹配行的时候,出现在主键和唯一键查询。
const和eq_ref的区别:
const一般出现在当前查询最多只有一个匹配行的情况下
eq_ref一般是多表关联,关联字段是唯一性索引,但是当前sql可能返回多行
systemsystem是const类型的特例,当查询的表只有一行的情况下,使用system。
NULL意味着Mysql能在优化阶段分解查询语句,在执行阶段甚至不用访问表或者索引
例如从索引列里选取最小值可以通过单独查询索引来完成。

possible_keys

这一列表示本次查询可以使用哪些索引。这是基于查询访问的列和使用的比较操作符来判断的。

key

这一列显示了Mysql决定采用哪个索引。优化器会选择查询成本最低的索引。

key_len

该列显示了Mysql在索引里使用的字节数。可以使用这个值来计算出具体使用了索引中的哪几个字段。这个字节数对应的是字段类型的字节数,和存储值无关。
注意点:

  1. 对于字符串类型,需要把字符列的字符集也考虑进去,比如utf8下一个字符最大占用3个字节,所以使用3字节来计算。
  2. 当索引字段为定长数据类型,比如char,int,datetime,需要有是否为空的标记,这个标记需要占用1个字节,当字段定义为非空的时候,是否为空的标记将不占用字节。
  3. 对于变长数据类型,比如:varchar,除了是否为空的标记外,还需要有长度信息,需要占用2个字节。

ref

这一列显示了当前的表在key列记录的索引中查询值所用的列或者常量。
举个例子:

  explain
  select * from 
  a inner join b
  on a.bid = b.id
tabletypekeyref
aALL
beq_refPRIMARYa.bid
这个例子里,b表走了主键索引,而走索引查询所使用的列就是a表的bid字段

rows

这是Mysql估算的,为了找到所需的行而要读取的行数,大体就是扫描行数的意思。这只是个估算,不一定准确,可以作为参考。

filtered

这一列显示的是针对扫描行里符合条件的记录数的百分比。rows * filtered/100 可以估算出将要和执行计划里前一个表关联的行数。
这个百分比应该是越大越好,越大代表扫描行数和最终结果集越接近。

extra

对于当前查询的额外信息。常见的见下表。

说明
Using index表示Mysql将使用覆盖索引,以避免访问表。
不要把覆盖索引和index访问类型搞混了。
覆盖索引指的是,索引中包含了需要返回的所有列(select的字段)。
Using where表示Mysql将在存储引擎检索行之后再进行过滤。
许多where条件里涉及索引中的列,当它读取索引时,就能被存储引擎校验。
因此不是所有带where子句的查询都会现实“Using where”。
有时“Using where”就是一个暗示:查询可受益于不同的索引(换个索引吧)
Using index ConditionIndex Condition Pushdown(ICP)是Mysql 5.6开始支持的一种优化方式。
使用ICP时,Mysql会在取出索引的同时把where的部分过滤操作放在存储引擎层进行(当存在只通过索引就可以进行where过滤时发生)。
在某些查询下可以大大减少SQL层对存储引擎层的查询。
Using temporary表示Mysql在对查询结果排序时会使用一个临时表
Using filesort表示Mysql会对结果使用一个外部索引排序,
而不是按索引次序从表里读取行。
Range checked for each record
(index map: N)
表示没有好用的索引,新的索引将在联接的每一行上重新估算。
N是显示在possible_keys列中索引的位图,并且是冗余的。
前5种在工作中会比较常见,掌握好可以解决80%的问题。

参考资料

《高性能Mysql》
《MySQL技术内幕-InnoDB存储引擎》

<think>我们刚刚讨论过MySQL的BETWEEN...AND...的闭区间特性,现在用户转向询问EXPLAIN执行计划结果的含义。用户参考了四篇关于EXPLAIN执行计划的文档(引用1-4),核心诉求是理解EXPLAIN输出中各列的含义。观察用户行为:这是技术细节的深挖,用户可能正在实际优化SQL性能。需要结构化呈现EXPLAIN的关键输出字段,并结合示例帮助理解。重点规划:1.开篇说明EXPLAIN的作用——展示SQL执行计划的关键信息(引用1/2/3的核心观点)2.用表格罗列EXPLAIN的主要输出列(id/select_type/table等),每列需包含含义和典型值3.对关键列(如type/Extra)作更细致的解释,因它们直接反映性能痛点4.补充一个具体示例,展示如何解读实际输出5.注意系统指令要求:数学公式用LaTeX格式,中英文混排时保持专业术语准确特别考虑:引用文档[4]提到"explainselect(select1fromactorwhereid=1)from(select*fromfilmwhereid=1)dd"这样的嵌套查询,解读时需注意id列和select_type列的关联性。最终结构:一、EXPLAIN命令概述(作用+用法)二、输出列详解表格(10个核心字段)三、重点字段深度解析(type/Extra的等级说明)四、示例解读五、总结建议</think> ### 📊 MySQL EXPLAIN执行计划结果详解 EXPLAIN命令用于分析SQL语句的执行计划,帮助优化查询性能。以下是其输出结果的核心字段详解(基于引用[1][2][3][4]): #### 一、核心字段解析 | **字段名** | **含义** | **典型值/说明** | |------------------|--------------------------------------------------------------------------|-------------------------------------------------------------------------------| | **id** | 查询的序列号(执行顺序) | 数值相同按顺序执行;不同时,值越大优先级越高 | | **select_type** | 查询类型 | `SIMPLE`(简单查询)、`PRIMARY`(外层查询)、`SUBQUERY`(子查询)等 [^3] | | **table** | 访问的表名 | 若为衍生表则显示`<derivedN>`(N为id值) | | **type** 🔑 | **访问类型**(性能关键) | `ALL`(全表扫描)→`index`→`range`→`ref`→`eq_ref`→`const`(性能依次升高)[^1] | | **key** | 实际使用的索引 | 若为`NULL`表示未用索引 | | **rows** | 预估扫描行数 | 值越大性能越差,需优化索引 | | **Extra** 🔍 | **额外信息**(重要优化线索) | ▶ `Using where`: 使用WHERE过滤<br>▶ `Using index`: 覆盖索引<br>▶ `Using temporary`: 用临时表<br>▶ `Using filesort`: 额外排序 | #### 二、关键字段深度解析 1. **type字段等级**(性能从低到高): $$ \text{ALL} \to \text{index} \to \text{range} \to \text{ref} \to \text{eq\_ref} \to \text{const} $$ - **range**:索引范围扫描(如`BETWEEN`、`IN()`) - **const**:通过主键/唯一索引找到一行(最优) 2. **Extra字段常见值**: - `Using filesort`: 表示需额外排序(如`ORDER BY`非索引列),可通过创建复合索引优化: ```sql -- 优化前(可能触发filesort) SELECT * FROM orders ORDER BY create_time; -- 优化后(复合索引避免排序) ALTER TABLE orders ADD INDEX idx_create_time (create_time); ``` - `Using temporary`: 需创建临时表(常见于`GROUP BY`非索引列),可通过索引优化。 #### 三、示例解读 ```sql EXPLAIN SELECT * FROM users WHERE age BETWEEN 18 AND 30 ORDER BY name; ``` | id | select_type | table | type | key | rows | Extra | |----|-------------|-------|-------|---------|------|----------------| | 1 | SIMPLE | users | range | idx_age | 1000 | Using filesort | **解读**: 1. 使用索引`idx_age`进行范围扫描(`type=range`) 2. 但`ORDER BY name`导致额外排序(`Using filesort`) 3. **优化建议**:创建复合索引 `(age, name)` #### 四、最佳实践 1. **优先关注**: - `type` 避免出现 `ALL`(全表扫描) - `Extra` 避免 `Using filesort` 和 `Using temporary` 2. **索引优化**: - 对`WHERE`、`JOIN`、`ORDER BY`涉及的列创建复合索引 - 使用覆盖索引(`Extra`显示`Using index`)减少回表查询 > 通过执行计划可定位性能瓶颈。例如`rows`值突增时需检查索引失效,`type`降级时需调整查询条件[^2]。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值