【MySQL从入门到精通】【高级篇】(二十四)EXPLAIN中select_type,partition,type,key,key_len字段的剖析

本文涉及的产品
云数据库 RDS MySQL,集群系列 2核4GB
推荐场景:
搭建个人博客
RDS MySQL Serverless 基础系列,0.5-2RCU 50GB
云数据库 RDS MySQL,高可用系列 2核4GB
简介: 上一篇文章我们介绍了【MySQL从入门到精通】【高级篇】(二十三)EXPLAIN的概述与table,id字段的剖析,重点对EXPLAIN命令进行了阐述,并且对table,id字段进行了剖析。这篇文章接着对EXPLAIN命令的其余字段进行解析,本文将介绍select_type,partition,type,key,key_len 字段的含义。其中:读者朋友们需要重点掌握 select_type,type 两个字段的含义。

1. 简介

上一篇文章我们介绍了【MySQL从入门到精通】【高级篇】(二十三)EXPLAIN的概述与table,id字段的剖析,重点对EXPLAIN命令进行了阐述,并且对table,id字段进行了剖析。这篇文章接着对EXPLAIN命令的其余字段进行解析,本文将介绍select_type,partition,type,key,key_len 字段的含义。其中:读者朋友们需要重点掌握 select_type,type 两个字段的含义。

2. 测试的表和数据

详细的测试表创建以及插入测试数据,请参见:【MySQL从入门到精通】【高级篇】(二十三)EXPLAIN的概述与table,id字段的剖析

3. select_type

一条大的查询语句里面可以包含若干个SELECT 关键字,每个SELECT关键字代表着一个小的查询语句, 而每个SELECT 关键字的FROM子句中都可以包含若干张表(这些表用来做连接查询),每一张表都对应着执行计划输出中的一条记录,对于在同一个SELECT关键字中的表来说,它们的id值是相同的。


MySQL为每一个SELECT关键字代表的小查询都定义了一个称之为select_type的属性,意思是我们只要知道了某个小查询的select_type属性,就知道了这个小查询在整个大查询中扮演了一个什么角色, 我们看一下select_type都能取得哪些值,请看官方文档:

名称 描述
SIMPLE 简单的查询(没有使用UNION 或者子查询(subqueries))
PRIMARY 主键查询
名称 描述
SIMPLE 简单的查询(没有使用UNION 或者子查询(subqueries))
PRIMARY 主键查询
DEPENDENT SUBQUERY 子查询中第一个查询,依赖外部查询
DEPENDENT UNION 在UNION中第二个或者更后面的查询语句,依赖外部查询
DERIVED 驱动表

MATERIALIZEDMateerialized 子查询UNCACHEABLE SUBQUERY子查询的结果不能被缓存,必须被用于外部查询的计算UNCACHEABLE UNIONUNION的第二个或者更后面的查询,数据不能被缓存

3.1. 连接查询也算是SIMPLE类型

EXPLAIN SELECT * FROM s1 INNER JOIN s2;

3.2. 包含UNION或者UNION ALL的情况

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


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


MySQL选择使用临时表来完成UNION查询的去重工作,针对该临时表的查询的select_type就是 UNION RESULT

EXPLAIN SELECT * FROM s1 UNION SELECT * FROM s2;

如果是UNION ALL 连接的话则不需要通过临时表来去重

EXPLAIN SELECT * FROM s1 UNION ALL SELECT * FROM s2;


3.3. 子查询

如果包含子查询的查询语句不能够转为对应的semi-join的形式,并且该子查询是不相关子查询。该子查询的第一个SELECT 关键字代表的那个查询的 select_type 就是SUBQUERY。

EXPLAIN SELECT * FROM s1 WHERE key1 IN (SELECT key1 FROM s2) OR key3='a'; 

如果包含子查询的查询语句不能欧转为对应的semi-join 的形式,并且该子查询是相关子查询,则该子查询的第一个 SELECT 关键字代表的那个查询的select_type 就是DEPENDENT SUBQUERY。

EXPLAIN SELECT * FROM s1 WHERE key1 IN(SELECT key1 FROM s2 WHERE s1.key1=s2.key2) OR key3='a';


需要注意的是,select_type为DEPENDENT SUBQUERY的查询可能会被执行多次。


在包含 UNION或者UNION ALL 的大查询中,如果各个小查询都依赖于外层查询的话,那除了最左边的那个小查询之外,其余的小查询的select_type 的值就是DEPENDENT UNION。

EXPLAIN SELECT * FROM s1 WHERE key1 IN (SELECT key1 FROM s2 WHERE key1='a' UNION SELECT key1 FROM s1 WHERE key1='a');


对于包含派生表的查询,该派生表对应的子查询的select_type 就是DERIVED

EXPLAIN SELECT * FROM (SELECT key1,COUNT(*) AS c FROM s1 GROUP BY key1) AS derived_s1 WHERE c>1;

当查询优化器在执行包含子查询的语句时,选择将子查询物化之后与外层查询进行连接查询时,该子查询对应的select_type 属性就是MATERIALIZED

EXPLAIN SELECT * FROM s1 WHERE key1 IN (SELECT key1 FROM s2); 

子查询被转化为了物化表。

4. partitions

partitions 代表分区表中的命中情况,非分区表,该项为NULL,一般情况下我们的查询语句的执行计划的partitions的列的值都是NULL。 该部分不重要,可以省略

5. type (非常重要)

执行计划的一条记录就代表着MySQL对某个表的执行查询时的访问方法,又称"访问类型",其中type列就表明了这个访问方法是啥,是较为重要的一个指标。比如,看到type列的值是ref,表明MySQL即将使用ref访问方法来执行对s1表的查询。

完整的访问方法如下:system,const,eq_ref,ref,fulltext,ref_or_null,index_merge,unique_subquery,index_subquery,range,index,ALL

5.1. system

当表中只有一条记录 并且该表使用的存储引擎的统计数据是精确的,比如MyISAM、Memory、那么对该表的访问方法就是system。比方说我们新建一个MyISAM表,并为其插入一条记录。

CREATE TABLE t(i int) ENGINE=MyISAM;
INSERT INTO t VALUES(1);

EXPLAIN SELECT * FROM t;

CREATE TABLE t2(i int) ENGINE=INNODB;
INSERT INTO t2 VALUES(1);
EXPLAIN SELECT * FROM t2;

5.2. const


const 表示通过索引一次就找到,const用于比较primary key或者unique索引,因为只需匹配一行数据,所以很快,如果将主键置于where列表中,mysql就能将该查询转换为一个const。

当我们根据主键或者唯一二级索引列与常数进行等值匹配时,对单表的访问方法就是const。

EXPLAIN SELECT * FROM s1 WHERE id=10005;
• 1

5.3. eq_ref

eq_ref:唯一性索引扫描,对于每个索引键,表中只有一条记录与之匹配。常见于主键或者唯一索引扫描。

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

EXPLAIN SELECT * FROM s1 INNER JOIN s2 ON s1.id=s2.id;

注意:ALL全表扫描的表是记录最少的表,如s1表。

5.4. ref

ref:非唯一性索引扫描,返回匹配某个单独值的所有行。本质上也是一种索引访问,它返回所有匹配某个单独值的行,然而它可能会找到多个符合条件的行,所以它应该属于查找和扫描的混合体。

EXPLAIN SELECT * FROM s1 WHERE key1='a';


5.5. ref_or_null

当对普通二级索引进行等值匹配查询,该索引列的type值就可能是ref_or_null。

EXPLAIN SELECT * FROM s1 WHERE key1='a' OR key1 is NULL;

5.6. index_merge

index_merge 表示在单表访问方法时在某些场景下可以使用Intersection、union、sort-union 这三种索引合并的方式来执行查询

EXPLAIN SELECT * FROM s1 WHERE key1='a' OR key3='a';

5.7. unique_subquery

unique_subquery 是针对在一些包含IN子查询的查询语句中,如果查询优化器决定将IN子查询转换为EXISTS 子查询,而且子查询可以使用到主键进行等值匹配的话,那么该子查询执行计划的type列的值就是 unique_subquery

EXPLAIN SELECT * FROM s1 WHERE key2 IN (SELECT id FROM s2 WHERE s1.key1=s2.key1) OR key3='a';

5.8. range

只检索给定范围的行,使用一个索引来选择行,key列显示使用了那个索引。一般就是在where语句中出现了 between、<、>、in等的查询。这种索引上的范围扫描比全表扫描要好。只需要开始于某个点,结束于另一个点,不用扫描全部索引。

EXPLAIN SELECT * FROM s1 WHERE key1 IN('a','b','c');

同上

EXPLAIN SELECT * FROM s1 WHERE key1>'a' AND key2<'b';

5.9. index

Full index Scan,index与ALL区别为index类型只遍历索引树。这通常为ALL块,应为索引文件通常比数据文件小。(Index与ALL虽然都是读全表,但index是从索引中读取,而ALL是从硬盘读取)

EXPLAIN SELECT key_part2 FROM s1 WHERE key_part3='a';

5.10 ALL (全表扫描)

ALL: Full Table Scan,遍历全表以找到匹配的行

EXPLAIN SELECT * FROM s1;

5.11 小结

type(访问类型)是sql查询优化中一个很重要的指标,结果值从好到坏依次是:

system > const > eq_ref > ref > fulltext > ref_or_null > index_merge > unique_subquery > index_subquery > range > index > ALL


其中比较重要的几个做了加粗处理,SQL性能优化的目标:至少要达到range级别,要求是ref级别,最好是const级别(阿里巴巴开发手册要求)

6. possible_keys和key

在EXPLAIN语句输出的执行计划中,possible_keys 列表示在某个查询语句中,对某个表执行单表查询时可能用到的索引有哪些。如果为NULL,则没有使用索引,比方说下边这个查询:

EXPLAIN SELECT * FROM s1 WHERE key1>'z' AND key3='a';

这里可能使用到的索引有 idx_key1和idx_key3,但是实际使用到索引是 idx_key3。

7. key_len

实际使用到的索引长度(即:字节数)

帮你检查是否充分的利用上了索引,值越大越好,主要针对联合索引,有一定的参考意义。

EXPLAIN SELECT * FROM s1 WHERE id=10005;


这里int本身占4个字节。

EXPLAIN SELECT * FROM s1 WHERE key2=10126;

这里key2是int类型,本身占用4个字节,并且其还被设置了一个唯一索引,占用一个非空字节,所以是5个字节。

EXPLAIN SELECT * FROM s1 WHERE key1='a';

这里key1的长度是100,而在utf-8中一个字符占用3个字节,那么就是100*3,key1有可能是空的情况,那么就需要+1,并且varchar是变长的类型,所以,还需要两个字节去记录实际长度是多少,那么就是 100*3+1+2=303。

7.1. 针对联合索引的情况

EXPLAIN SELECT * FROM s1 WHERE key_part1='a';
EXPLAIN SELECT * FROM s1 WHERE key_part1='a' and key_part2='b';

这里的两个查询都使用到了 idx_key_part索引,该索引是一个联合索引,而下面的查询语句的key_len比上面的查询语句的key_len要大。所以,下面的查询效果要比上面的查询效果要好。

总结

本文详细介绍了EXPLAIN中select_type,partition,type,key,key_len字段。


相关实践学习
如何在云端创建MySQL数据库
开始实验后,系统会自动创建一台自建MySQL的 源数据库 ECS 实例和一台 目标数据库 RDS。
全面了解阿里云能为你做什么
阿里云在全球各地部署高效节能的绿色数据中心,利用清洁计算为万物互联的新世界提供源源不断的能源动力,目前开服的区域包括中国(华北、华东、华南、香港)、新加坡、美国(美东、美西)、欧洲、中东、澳大利亚、日本。目前阿里云的产品涵盖弹性计算、数据库、存储与CDN、分析与搜索、云通信、网络、管理与监控、应用服务、互联网中间件、移动服务、视频服务等。通过本课程,来了解阿里云能够为你的业务带来哪些帮助 &nbsp; &nbsp; 相关的阿里云产品:云服务器ECS 云服务器 ECS(Elastic Compute Service)是一种弹性可伸缩的计算服务,助您降低 IT 成本,提升运维效率,使您更专注于核心业务创新。产品详情: https://www.aliyun.com/product/ecs
相关文章
|
2月前
|
安全 关系型数据库 MySQL
PHP与MySQL交互:从入门到实践
【9月更文挑战第20天】在数字时代的浪潮中,掌握PHP与MySQL的互动成为了开发动态网站和应用程序的关键。本文将通过简明的语言和实例,引导你理解PHP如何与MySQL数据库进行对话,开启你的编程之旅。我们将从连接数据库开始,逐步深入到执行查询、处理结果,以及应对常见的挑战。无论你是初学者还是希望提升技能的开发者,这篇文章都将为你提供实用的知识和技巧。让我们一起探索PHP与MySQL交互的世界,解锁数据的力量!
|
2月前
|
关系型数据库 MySQL 数据库
MySQL基本操作入门指南
MySQL基本操作入门指南
89 0
|
17天前
|
分布式计算 关系型数据库 MySQL
SpringBoot项目中mysql字段映射使用JSONObject和JSONArray类型
SpringBoot项目中mysql字段映射使用JSONObject和JSONArray类型 图像处理 光通信 分布式计算 算法语言 信息技术 计算机应用
36 8
|
2月前
|
SQL 关系型数据库 MySQL
MySQL 8.0报错--1118-Row size too large. The maximum row size for the used table type, not counting BLOBs,is 8126,
MySQL 8.0报错--1118-Row size too large. The maximum row size for the used table type, not counting BLOBs,is 8126,
MySQL 8.0报错--1118-Row size too large. The maximum row size for the used table type, not counting BLOBs,is 8126,
|
26天前
|
关系型数据库 MySQL Java
SpringBoot项目中mysql字段映射使用JSONObject和JSONArray类型
SpringBoot项目中mysql字段映射使用JSONObject和JSONArray类型
26 0
|
2月前
|
SQL 关系型数据库 MySQL
MySQL数据库中给表添加字段并设置备注的脚本编写
通过上述步骤,你可以在MySQL数据库中给表成功添加新字段并为其设置备注。这样的操作对于保持数据库结构的清晰和最新非常重要,同时也帮助团队成员理解数据模型的变化和字段的具体含义。在实际操作中,记得调整脚本以适应具体的数据库和表名称,以及字段的详细规范。
63 8
|
1月前
|
SQL 存储 关系型数据库
MySQL新增字段/索引会不会锁表?
MySQL新增字段/索引会不会锁表?
131 0
|
1月前
|
SQL 关系型数据库 MySQL
MySQL EXPLAIN该如何分析?
本文将详细介绍MySQL中`EXPLAIN`关键字的工作原理及结果字段解析,帮助优化查询性能。`EXPLAIN`可显示查询SQL的执行计划,其结果包括`id`、`select_type`、`table`等字段。通过具体示例和优化建议,帮助你理解和应用`EXPLAIN`,提升数据库查询效率。
87 0
|
1月前
|
SQL 关系型数据库 MySQL
MySQL 查询某个字段含有字母数字的值
MySQL 查询某个字段含有字母数字的值
67 0
|
1月前
|
存储 关系型数据库 MySQL
MySQL 字符字段长度设置详解:语法、注意事项和示例
MySQL 字符字段长度设置详解:语法、注意事项和示例
202 0
下一篇
无影云桌面