EXPLAIN 语句输出的各个列解释

# EXPLAIN 语句输出的各个列解释

列名描述
id在一个大的查询语句中每个 SELECT 关键字都对应一个唯一的 id
select_typeSELECT 关键字对应的那个查询的类型
table表名
partitions匹配的分区信息
type针对单表的访问方法
possible_keys可能用到的索引
key实际上使用的索引
key_len实际使用到的索引长度
ref当使用索引列等值查询时,与索引列进行等值匹配的对象信息
rows预估的需要读取的记录条数
filtered某个表经过搜索条件过滤后剩余记录条数的百分比
Extra一些额外的信息

# select_type

每一个 SELECT 关键字代表的小查询都定义了一个称之为 select_type 的属性,意思是我们 只要知道了某个小查询的 select_type 属性,就知道了这个小查询在整个大查询中扮演了一个什么角色

image-20220223091837507

# SIMPLE

查询语句中不包含 UNION 或者子查询的查询都算作是 SIMPLE 类型,连接查询也算是 SIMPLE 类型。

# PRIMARY

对于包含 UNION 、 UNION ALL 或者子查询的大查询来说,它是由几个小查询组成的,其中最左边的那个查询 的 select_type 值就是 PRIMARY

image-20220222112249591

# UNION

对于包含 UNION 或者 UNION ALL 的大查询来说,它是由几个小查询组成的,其中除了最左边的那个小查询以 外,其余的小查询的 select_type 值就是 UNION

# UNION RESULT

MySQL 选择使用临时表来完成 UNION 查询的去重工作,针对该临时表的查询的 select_type 就是 UNION RESULT ,例子上边有,就不赘述了。

# 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

不常用,就不多唠叨了。

# UNCACHEABLE UNION

不常用,就不多唠叨了。

# type

执行计划的一条记录就代表着 MySQL 对某个表的执行查询时的访问方法

system: 当表中只有一条记录并且该表使用的存储引擎的统计数据是精确的,比如MyISAM、Memory,那么对该表的访问方法就是 system。

const: 根据主键或者唯一二级索引列与常数进行等值匹配

eq_ref: 在连接查询时,如果被驱动表是通过主键或者唯一二级索引列等值匹配的方式进行访问的(如果该主键或者唯一二级索引是联合索引的话,所有的索引列都必须进行等值比较),则对该被驱动表的访问方法就是eq_ref

ref: 搜索条件为二级索引列与常数等值比较来定位多条记录,采用二级索引来执行查询的访问方法

fulltext 全文索引

ref_or_null: 当对普通二级索引进行等值匹配查询,该索引列的值也可以是 NULL 值时,那么对该表的访问方法就可能是ref_or_null

index_merge: 一般情况下对于某个表的查询只能使用到一个索引,但我们唠叨单表访问方法时特意强调了在某些场景下可以使用 Intersection 、 Union 、 Sort-Union 这三种索引合并的方式来执行查询,会使用到多个索引。

unique_subquery: 类似于两表连接中被驱动表的 eq_ref 访问方法, unique_subquery 是针对在一些包含 IN 子查询的查询语句中,如果查询优化器决定将 IN 子查询转换为 EXISTS 子查询,而且子查询可以使用到主键进行等值匹配的话,那么该子查询执行计划的 type 列的值就是 unique_subquery

index_subquery: index_subquery 与 unique_subquery 类似,只不过访问子查询中的表时使用的是普通的索引(unique_subquery之前用的是主键索引或者一二级索引)。

range: 如果使用索引获取某些 范围区间的记录,那么就可能使用到 range 访问方法

index: 当我们可以使用索引覆盖,但需要扫描全部的索引记录时,该表的访问方法就是 index。

ALL: 全表扫描。

# possible_keys和key

possible_keys 列表示在某个查询语句中,对某个表执行单表查询时可能用到的索引有哪些, key 列表示实际用到的索引有哪些。

# key_len

key_len 列表示当优化器决定使用某个索引执行查询时,该索引记录的最大长度,它是由这三个部分构成的:

  • 对于使用固定长度类型的索引列来说,它实际占用的存储空间的最大长度就是该固定值,对于指定字符集的变长类型的索引列来说,比如某个索引列的类型是 VARCHAR(100) ,使用的字符集是 utf8 ,那么该列实际占用的最大存储空间就是 100 × 3 = 300 个字节。
  • 如果该索引列以存储 NULL 值,则 key_len 比不可以存储 NULL 值时多1个字节。
  • 对于变长字段来说,都会有2个字节的空间来存储该变长列的实际长度。

例子

image-20220222202111013

提示:有的同学可能有疑问:你在前边唠叨 InnoDB 行格式的时候不是说,存储变长字段的实际长度不是可能占用1个字节或者2个字节么?为什么现在

不管三七二十一都用了 2 个字节?这里需要强调的一点是,执行计划的生成是在MySQL server 层中的功能,并不是针对具体某个存储引擎的功能,设计

MySQL 的大叔在执行计划中输出key_len 列主要是为了让我们区分某个使用联合索引的查询具体用了几个索引列而不是为了准确的说明针对某个具体

存储引擎存储变长字段的实际长度占用的空间到底是占用1个字节还是2个字节

# ref

# rows

如果查询优化器决定使用全表扫描的方式对某个表执行查询时,执行计划的 rows 列就代表预计需要扫描的行数,如果使用索引来执行查询时,执行计划的 rows 列就代表预计扫描的索引记录行数

# filtered

之前在分析连接查询的成本时提出过一个 condition filtering 的概念,就是 MySQL 在计算驱动表扇出时采用的一个策略:

  • 如果使用的是全表扫描的方式执行的单表查询,那么计算驱动表扇出时需要估计出满足搜索条件的记录到底有多少条。
  • 如果使用的是索引执行的单表扫描,那么计算驱动表扇出的时候需要估计出满足除使用到对应索引的搜索条件外的其他搜索条件的记录有多少条。

连接查询中驱动表对应的执行计划记录的filtered 值,比方说下边这个查询:

image-20220222204006642

从执行计划中可以看出来,查询优化器打算把 s1 当作驱动表, s2 当作被驱动表。我们可以看到驱动表 s1 表的执行计划的 rows 列为 9688 , filtered 列为 10.00 ,这意味着驱动表 s1 的扇出值就是 9688 × 10.00% = 968.8 ,这说明还要对被驱动表执行大约 968 次查询。

Extra 列是用来说明一些额外信息的,我们可以通过这些额外信息来更准确的理解 MySQL 到底将如何执行给定的查询语句

欢迎关注ggball博客

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值