explain结果列说明:
explain 列名 |
描述 |
id |
在一个大的查询语句中每个SELECT关键字都对应一个唯一的id |
select_type |
SELECT关键字对应的那个查询的类型 |
table |
表名 |
partitions |
匹配的分区信息 |
type |
针对单表的访问方法 |
possible_keys |
可能用到的索引 |
key |
实际上使用的索引 |
key_len |
实际使用到的索引长度 |
ref |
当使用索引列等值查询时,与索引列进行等值匹配的对象信息 |
rows |
预估的需要读取的记录条数 |
filtered |
某个表经过搜索条件过滤后剩余记录条数的百分比 |
Extra |
一些额外的信息 |
case:
普通查询
中,每出现一个SELECT
关键字,就会分配一个唯一的id
值
| mysql> EXPLAIN SELECT * FROM s1 WHERE key1 = 'a'; |
| +----+-------------+-------+------------+------+---------------+----------+---------+-------+------+----------+-------+ |
| | id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra | |
| +----+-------------+-------+------------+------+---------------+----------+---------+-------+------+----------+-------+ |
| | 1 | SIMPLE | s1 | NULL | ref | idx_key1 | idx_key1 | 303 | const | 8 | 100.00 | NULL | |
| +----+-------------+-------+------------+------+---------------+----------+---------+-------+------+----------+-------+ |
| 1 row in set, 1 warning (0.03 sec) |
连接查询
,一个select关键字后边的from子句中可以跟随多个表,所以在连接查询的执行计划中,每个表都会对应一条记录,但是这些记录的id值都是相同的
| mysql> EXPLAIN SELECT * FROM s1 INNER JOIN s2; |
| + |
| | id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra | |
| + |
| | 1 | SIMPLE | s1 | NULL | ALL | NULL | NULL | NULL | NULL | 9688 | 100.00 | NULL | |
| | 1 | SIMPLE | s2 | NULL | ALL | NULL | NULL | NULL | NULL | 9954 | 100.00 | Using join buffer (Block Nested Loop) | |
| + |
| 2 rows in set, 1 warning (0.01 sec) |
子查询
,可能涉及多个SELECT
关键字,所以在包含子查询的查询语句的执行计划中,每个SELECT
关键字都会对应一个唯一的id
值
| mysql> EXPLAIN SELECT * FROM s1 WHERE key1 IN (SELECT key1 FROM s2) OR key3 = 'a'; |
| + |
| | id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra | |
| + |
| | 1 | PRIMARY | s1 | NULL | ALL | idx_key3 | NULL | NULL | NULL | 9688 | 100.00 | Using where | |
| | 2 | SUBQUERY | s2 | NULL | index | idx_key1 | idx_key1 | 303 | NULL | 9954 | 100.00 | Using index | |
| + |
| 2 rows in set, 1 warning (0.02 sec) |
子查询重写变成连接查询
,查询优化器可能对涉及子查询的查询语句进行重写,从而转换为连接查询
| mysql> EXPLAIN SELECT * FROM s1 WHERE key1 IN (SELECT key3 FROM s2 WHERE common_field = 'a'); |
| + |
| | id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra | |
| + |
| | 1 | SIMPLE | s2 | NULL | ALL | idx_key3 | NULL | NULL | NULL | 9954 | 10.00 | Using where; Start temporary | |
| | 1 | SIMPLE | s1 | NULL | ref | idx_key1 | idx_key1 | 303 | xiaohaizi.s2.key3 | 1 | 100.00 | End temporary | |
| + |
| 2 rows in set, 1 warning (0.00 sec) |
UNION
子句的查询语句,
会多出一个临时表记录用来做去重逻辑
| mysql> EXPLAIN SELECT * FROM s1 UNION SELECT * FROM s2; |
| + |
| | id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra | |
| + |
| | 1 | PRIMARY | s1 | NULL | ALL | NULL | NULL | NULL | NULL | 9688 | 100.00 | NULL | |
| | 2 | UNION | s2 | NULL | ALL | NULL | NULL | NULL | NULL | 9954 | 100.00 | NULL | |
| | NULL | UNION RESULT | <union1,2> | NULL | ALL | NULL | NULL | NULL | NULL | NULL | NULL | Using temporary | |
| + |
| 3 rows in set, 1 warning (0.00 sec) |
UNION ALL
就不需要为最终的结果集进行去重,所以没有临时表
| mysql> EXPLAIN SELECT * FROM s1 UNION ALL SELECT * FROM s2; |
| + |
| | id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra | |
| + |
| | 1 | PRIMARY | s1 | NULL | ALL | NULL | NULL | NULL | NULL | 9688 | 100.00 | NULL | |
| | 2 | UNION | s2 | NULL | ALL | NULL | NULL | NULL | NULL | 9954 | 100.00 | NULL | |
| + |
| 2 rows in set, 1 warning (0.01 sec) |
select_type枚举:
名称 |
描述 |
SIMPLE |
查询语句中不包含UNION 或者子查询的查询都算作是SIMPLE 类型 |
PRIMARY |
对于包含UNION 、UNION ALL 或者子查询的大查询,其中最左边的那个查询的select_type 值就是PRIMARY |
UNION |
对于包含UNION 、UNION ALL 或者子查询的大查询,除了最左边的那个小查询以外,其余的小查询的select_type 值就是UNION |
UNION RESULT |
UNION 查询的去重工作中使用到的临时表的查询 |
SUBQUERY |
如果包含子查询的查询语句不能够转为对应的semi-join 的形式,并且该子查询是不相关子查询,并且查询优化器决定采用将该子查询物化的方案来执行该子查询时,该子查询的第一个SELECT 关键字代表的那个查询的select_type 就是SUBQUERY |
DEPENDENT SUBQUERY |
如果包含子查询的查询语句不能够转为对应的semi-join 的形式,并且该子查询是相关子查询,则该子查询的第一个SELECT 关键字代表的那个查询的select_type 就是DEPENDENT SUBQUERY |
DEPENDENT UNION |
在包含UNION 或者UNION ALL 的大查询中,如果各个小查询都依赖于外层查询的话,那除了最左边的那个小查询之外,其余的小查询的select_type 的值就是DEPENDENT UNION |
DERIVED |
对于采用物化的方式执行的包含派生表的查询,该派生表对应的子查询的select_type 就是DERIVED |
MATERIALIZED |
当查询优化器在执行包含子查询的语句时,选择将子查询物化之后与外层查询进行连接查询时,该子查询对应的select_type 属性就是MATERIALIZED |
UNCACHEABLE SUBQUERY |
A subquery for which the result cannot be
cached and must be re-evaluated for each row of the outer query |
UNCACHEABLE UNION |
The second or later select in a UN´ION
that belongs to an uncacheable subquery (see UNCACHEABLE SUBQUERY) |
type 枚举:
枚举值 |
描述 |
system |
当表中只有一条记录 并且是
MyISAM、Memory 引擎 |
const |
根据主键索引列 或者唯一二级索引列 与常量 进行等值匹配 的方法 |
eq_ref |
在连接查询 时,被驱动表 通过主键 或者唯一二级索引列 进行等值匹配的方法 |
ref |
普通二级索引列 与常量 进行等值匹配 查询某个表时,可能 是ref |
fulltext |
全文索引 |
ref_or_null |
普通二级索引 与常量 进行等值匹配 查询某个表,且该索引列的值也可以是NULL 值 |
index_merge |
使用索引合并 的方式来执行查询 |
unique_subquery |
查询优化器决定将IN 子查询转换为EXISTS 子查询,且子查询 可以使用到主键 进行等值匹配 |
index_subquery |
同unique_subquery,
只不过子查询 中的表时使用普通的索引 进行等值匹配 |
range |
使用索引 获取某些范围区间 的记录 |
index |
使用覆盖索引 ,
但需要扫描全部的索引记录的方法 |
ALL |
全表扫描 |
possible_keys和key:
possible_keys
列表示在某个查询语句中,对某个表执行单表查询时可能用到的索引有哪些,key
列表示实际用到的索引有哪些
注意:possible_keys
越多,查询优化器计算查询成本时就得花费更长时间
key_len:
key_len
:
表示当优化器决定使用某个索引执行查询时,该索引记录的最大字节长度,单位:字节
- 计算规则:
- 固定长度类型的索引列:
- 实际占用的存储空间的最大长度就是该固定值
- e.g.
CAHR(M)
ASCII字符集
- 计算:
key_len
= M * 1
- 可变长度字符集、可变长类型的索引列:
- 需要考虑
字符集
、索引列字符个数
、NUll值列表
、变长字段长度列表
- e.g.
VARCHAR(100)
utf8字符集
- 该列实际占用的最大存储空间:
100 × 3 = 300
个字节
- NUll值列表:1字节(一般来说索引为NOT NULL,
则不会有这1字节开销)
- 变长字段长度列表:2字节
- 计算:
key_len
= 300 + 1 + 2
- 作用:
ref:
枚举值 |
描述 |
const |
常量等值匹配; e.g. … = 1 |
func |
函数等值匹配; e.g. … =
UPPER(s1.key1) |
某个字段 |
字段等值匹配,会把库名也打印出; e.g. … =
s1.key1 |
当使用索引列等值匹配的条件去执行查询时(访问方法是const
、eq_ref
、ref
、ref_or_null
、unique_subquery
、index_subquery
之一),ref
列展示的就是与索引列作等值匹配具体内容,比如只是一个常数CONST
或者是某个列t.id
rows:
- 作用:查询优化器给出的
预计
需要扫描的行数,预估值
非精确值
- 场景:
- 如果查询优化器决定使用全表扫描执行查询时,
rows
列就代表预计需要扫描的行数
- 如果查询优化器决定使用索引查询时,
rows
列就代表预计扫描的索引记录行数
filtered:
- 作用:评估连表查询时,
驱动表
的扇出情况。扇出值表示驱动表符合条件的记录数n,在被驱动表中还需要n次查询
- 扇出值 = Rows * filtered
- 使用说明:
- 单表查询:
- 全表扫描:
filtered
列就代表查询优化器预测在这rows条记录中,满足全部搜索条件的比例
- 索引:
filtered
列就代表查询优化器预测在这rows条记录中,满足除使用到对应索引的搜索条件外,满足剩余搜索条件的比例
- 连表查询: 含义:扇出值:n = rows *
filtered。在对驱动表一次访问之后(需要扫描rows条记录),对被驱动表执行大约n次查询
### Extra: |常见的枚举值|描述|是否互斥| |:—-|:—-| |
Using index
| 使用索引覆盖的特性,即无需回表 |是| |
Using index condition
|
使用索引下推的特性,减少回表次数。(使用索引扫描出部分条件的结果,然后将这写临时结果再进行剩余条件匹配,最后再回表)
|是| |Using where
| 1.全表扫描且条件匹配 2.
使用到索引搜索,且剩余的条件判断无法通过索引覆盖、索引下推进行优化,必须直接回表
|是| |Using filesort
|
使用了文件排序。无法通过索引排序得到结果集,必须通过内存排序、磁盘排序才能得到结果|否|
|Using temporary
|
使用了临时表来排序、去重、分组。无法通过索引排序得到结果集,通过建立内部的临时表来执行|否|
|Using join buffer (Block Nested
Loop)|连接查询执行过程中,被驱动表``不能利用索引
,则会分配基于块的嵌套循环算法
的内存|是|
|Using intersect(…)
|使用Intersect
索引合并的方式执行查询|是| |Using union(…)
|使用Union
索引合并的方式执行查询|是| |Using sort_union(…)
|使用Sort-Union
索引合并的方式执行查询|是|
本文作者:navyum
本文链接:https://www.cnblogs.com/navyum/p/18509409
版权声明:本作品采用知识共享署名-非商业性使用-禁止演绎 2.5 中国大陆许可协议进行许可。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步