MySQL中explain的用法

执行结果各字段的含义

EXPLAIN + SQL语句
如:

EXPLAIN SELECT * FROM test

执行结果:

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

EXPLAIN各列作用

为了让大家有比较好的体验,我们调整了下 EXPLAIN 输出列的顺序。

1. table

表名不论我们的查询语句有多复杂,里面包含了多少个表,到最后也是需要对每个表进行单表访问的,所以MySQL规定EXPLAIN语句输出的每条记录都对应着某个单表的访问方法,该条记录的table列代表着该表的表名(有时不是真实的表名字,可能是简称)

#1. table:表名
#查询的每一行记录都对应着一个单表
explain select count(*) from s1;

image-20220326120805996

这里只用到s1这一张表,所以结果只有一条数据。

#s1:驱动表  s2:被驱动表
EXPLAIN SELECT * FROM s1 INNER JOIN s2;
# 驱动表和被驱动表是 优化器决定的,他认为哪个比较好久用哪个

由于驱动表和被驱动表是由优化器决定的,因此就像这里:s1 INNER JOIN s2 。不一定是s1就是驱动表,结果中s1不一定总在s2上面!

image-20220326121611806

这里用了内连接,涉及两张表,结果就有两条数据。

用到多少个表,就会有多少条记录(临时表也算在记录里面)

2.id

正常来说一个select 一个id ,也有例外的可能,查询优化器做了优化

1.mysql> EXPLAIN SELECT * FROM s1 WHERE key1 = 'a';

image-20220326122616487

这里只有一个select,所以结果也只有一种id2.mysql> EXPLAIN SELECT * FROM s1 INNER JOIN s2;

image-20220326122717663

这里虽然有两张表,但只有一个select语句,因此执行结果中只有一种id。3.mysql> EXPLAIN SELECT * FROM s1 WHERE key1 IN (SELECT key1 FROM s2) OR key3 = 'a';

image-20220326122751920

这里出现了子查询,有两个select,因此有两种id。先执行id越大(越接近1越小),越先执行。这里就先执行id为2的查询。

几种特殊情况

1.查询优化器优化

 ######查询优化器可能对涉及子查询的查询语句进行重写,转变为多表查询的操作########EXPLAIN SELECT * FROM s1 WHERE key1 IN (SELECT key2 FROM s2 WHERE common_field = 'a');

运行结果: id 只有一种,原因是查询优化器做了优化,变为了多表查询

image-20220326122857145

2.Union去重

原本想的1个select 一个 id , 预计两个。

 #Union去重
# union 去重,union all 不去重
EXPLAIN SELECT * FROM s1 UNION SELECT * FROM s2;

image-20220326123056983

注:这里用的是union,会把s1和s2取交集的集合做成临时表,在这个临时表里面去重。因此有三条记录
可以看到第三条数据的Extra字段表示:Using temporary。说明当前表是临时表(一条记录就是一张表)
因为前面说了,多少种id对应多少个select语句。但这里只有两个select,所以第三条语句的id为NULL。# union all 不去重  所以不需要放在临时表里面
mysql> EXPLAIN SELECT * FROM s1 UNION ALL SELECT * FROM s2;

image-20220326123147690

不去重,所以不用建立临时表,因此结果只有两条数据(两张表)

小结:

  • id如果相同,可以认为是一组,从上往下顺序执行
  • 在所有组中,id值越大,优先级越高,越先执行
  • 关注点:id号每个号码,表示一趟独立的查询, 一个sql的查询趟数越少越好。因为id种类越多,表示嵌套越多。三层嵌套,三种id,就像Java中的时间复杂度O(n³)一样。而多表连接查询的方式就相当于加法只会有三个一样的id,一种id,三张表连接就像时间复杂度为O(x+y+z)一样,效率高很多。

3.select_type

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

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

名称描述
SIMPLESimple SELECT (not using UNION or subqueries)
PRIMARYOutermost SELECT
UNIONSecond or later SELECT statement in a UNION
UNION RESULTResult of a UNION
SUBQUERYFirst SELECT in subquery
DEPENDENT SUBQUERYFirst SELECT in subquery, dependent on outer query
DEPENDENT UNIONSecond or later SELECT statement in a UNION, dependent on outer query
DERIVEDDerived table
MATERIALIZEDMaterialized subquery
UNCACHEABLE SUBQUERYA subquery for which the result cannot be cached and must be re-evaluated for each row of the outer query
UNCACHEABLE UNIONThe second or later select in a UNION that belongs to an uncacheable subquery (see UNCACHEABLE SUBQUERY)
  • SIMPLE

     # 查询语句中不包含`UNION`或者子查询的查询都算作是`SIMPLE`类型EXPLAIN SELECT * FROM s1;#连接查询也算是`SIMPLE`类型EXPLAIN SELECT * FROM s1 INNER JOIN s2;
  • PRIMARY 与 UNION与 UNION RESULT

    • UNION RESULT

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

    #对于包含`UNION`或者`UNION ALL`或者子查询的大查询来说,它是由几个小查询组成的,其中最左边的那个
    #查询的`select_type`值就是`PRIMARY`#对于包含`UNION`或者`UNION ALL`的大查询来说,它是由几个小查询组成的,其中除了最左边的那个小查询
    #以外,其余的小查询的`select_type`值就是`UNION`#`MySQL`选择使用临时表来完成`UNION`查询的去重工作,针对该临时表的查询的`select_type`就是`UNION RESULT` 	

    测试sql:

     EXPLAIN SELECT * FROM s1 UNION SELECT * FROM s2;	
    

    image-20220326125611904

    说明:这里s1 union s2,s1(由优化器决定,不一定哪张表就在最左边,这里刚好是s1)在最左边,s1表的select_type 为 `PRIMARY`。由于发生了去重,产生临时表<union1,2> 该表的select_type 为
    `UNION RESULT` 。而其他的表s2的`select_type`值就是`UNION`EXPLAIN SELECT * FROM s1 UNION ALL SELECT * FROM s2;
    

    image-20220326125627303

  • SUBQUERY

           如果包含子查询的查询语句优化器不能够转为对应的semi-join(多表连接)的形式,并且该子查询是不相关子查询,并且查询优化器决定采用将该子查询物化的方案来执行该子查询时,该子查询的第个SELECT 关键字代表的那个查询 的select_type就是 SUBQUERY,比如下边这个查询:

     #子查询:#如果包含子查询的查询语句不能够转为对应的`semi-join`的形式,并且该子查询是不相关子查询。#该子查询的第一个`SELECT`关键字代表的那个查询的`select_type`就是`SUBQUERY`EXPLAIN SELECT * FROM s1 WHERE key1 IN (SELECT key1 FROM s2) OR key3 = 'a';

image-20220326122751920

说明:这里s1的id最小,表示该表的查询在最外面一层,因此其select_type = 'PRIMARY',而s2的子查询是不相关子查询,因此select_type = 'SUBQUERY'。

  • DERIVED

    derived : 衍生,派生

     #对于包含`派生表`的查询,该派生表对应的子查询的`select_type`就是`DERIVED`EXPLAIN SELECT * FROM (SELECT key1, COUNT(*) AS c FROM s1 GROUP BY key1) AS derived_s1 WHERE c > 1;
    

    image-20220326141653065

    说明:首先有两个select对应两种id,这里的子查询用到了s1,table就是s1。而子查询的结果作为一张表供外面查询使用。因此外面表的table为derived2(2是子查询的id)。而子查询由于是派生出来作为表供查询的,因此select_type为'DERIVED'。                                                      

  • MATERIALIZED

    materialized: 英 [məˈtɪəri:əˌlaɪzd] 具体化

    #当查询优化器在执行包含子查询的语句时,选择将子查询物化之后与外层查询进行连接查询时,
    #该子查询对应的`select_type`属性就是`MATERIALIZED`
    EXPLAIN SELECT * FROM s1 WHERE key1 IN (SELECT key1 FROM s2); #子查询被转为了物化表 

image-20220326142034981

4.partitions (可略)

  • 代表分区表中的命中情况,非分区表,该项为NULL。一般情况下我们的查询语句的执行计划的partitions列的值都是NULL。
  • https://dev.mysql.com/doc/refman/5.7/en/alter-table-partition-operations.html
  • 如果想详细了解,可以如下方式测试。创建分区表:
-- 创建分区表,
-- 按照id分区,id<100 p0分区,其他p1分区
CREATE TABLE user_partitions (id INT auto_increment,NAME VARCHAR(12),PRIMARY KEY(id))PARTITION BY RANGE(id)(PARTITION p0 VALUES less than(100),PARTITION p1 VALUES less than MAXVALUE
);
DESC SELECT * FROM user_partitions WHERE id>200;

查询id大于200(200>100,p1分区)的记录,查看执行计划,partitions是p1,符合我们的分区规则

image-20220325201510359

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 。

我们详细解释一下:

  • system

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

    mysql> CREATE TABLE t(i int) Engine=MyISAM;
    Query OK, 0 rows affected (0.05 sec)mysql> INSERT INTO t VALUES(1);
    Query OK, 1 row affected (0.01 sec)

    然后我们看一下查询这个表的执行计划:

    mysql> EXPLAIN SELECT * FROM t;
    +----+-------------+-------+------------+--------+
    | id | select_type | table | partitions | type   |
    +----+-------------+-------+------------+--------+
    |  1 | SIMPLE      | t     | NULL       | system |
    +----+-------------+-------+------------+--------+
    1 row in set, 1 warning (0.00 sec)

    这里如果是 innodb 会变成ALL , 因为innodb系统不会存条数字段。。MyISAM会存储这么一个字段

  • const

     #当我们根据主键或者唯一二级索引列与常数进行等值匹配时,对单表的访问方法就是`const`EXPLAIN SELECT * FROM s1 WHERE id = 10005;EXPLAIN SELECT * FROM s1 WHERE key2 = '10066';

注意:这里id是主键,key2是唯一二级索引。改成key3,由于不唯一,所以type变为All

  • eq_ref

     #在连接查询时,如果被驱动表是通过主键或者唯一二级索引列等值匹配的方式进行访问的#(如果该主键或者唯一二级索引是联合索引的话,所有的索引列都必须进行等值比较),则#对该被驱动表的访问方法就是`eq_ref`EXPLAIN SELECT * FROM s1 INNER JOIN s2 ON s1.id = s2.id;
    
     

    从执行计划的结果中可以看出,MySQL打算将s2作为驱动表,s1作为被驱动表,重点关注s1的访问 方法是 eq_ref ,表明在访问s1表的时候可以 通过主键的等值匹配 来进行访问。

注意:这个s2表的查询先执行,执行完以后s2.id就是一个具体的值。然后再执行s1.id(主键) = 某一个具体的值(s2.id的执行结果) 速度就也挺快的了。

  • ref

     #当通过普通的二级索引列与常量进行等值匹配时来查询某个表,那么对该表的访问方法就可能是`ref`EXPLAIN SELECT * FROM s1 WHERE key1 = 'a';

    tips: 类型相同才可以走索引

    EXPLAIN SELECT * FROM s1 WHERE key3 = 10066;
    # 这个是不会走索引的 因为key3 是字符串
    # 类型不一样,mysql会加函数,进行隐式转换,一旦加上函数,就不会走索引了。

    隐式转换以后,索引可能失效!

  • ref_or_null

     #当对普通二级索引进行等值匹配查询,该索引列的值也可以是`NULL`值时,那么对该表的访问方法#就可能是`ref_or_null`EXPLAIN SELECT * FROM s1 WHERE key1 = 'a' OR key1 IS NULL;

  • index_merge

     #单表访问方法时在某些场景下可以使用`Intersection`、`Union`、#`Sort-Union`这三种索引合并的方式来执行查询EXPLAIN SELECT * FROM s1 WHERE key1 = 'a' OR key3 = 'a';

    从执行计划的 type 列的值是 index_merge 就可以看出,MySQL 打算使用索引合并的方式来执行 对 s1 表的查询。

  • 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';
  • index_subquery

    EXPLAIN SELECT * FROM s1 WHERE common_field IN (SELECT key3 FROM s2 where
    s1.key1 = s2.key1) OR key3 = 'a';
  • range

    #如果使用索引获取某些`范围区间`的记录,那么就可能使用到`range`访问方法
    EXPLAIN SELECT * FROM s1 WHERE key1 IN ('a', 'b', 'c');#同上
    EXPLAIN SELECT * FROM s1 WHERE key1 > 'a' AND key1 < 'b';
  • index

    #当我们可以使用索引覆盖,但需要扫描全部的索引记录时,该表的访问方法就是`index`
    EXPLAIN SELECT key_part2 FROM s1 WHERE key_part3 = 'a';

    索引覆盖,INDEX idx_key_part(key_part1, key_part2, key_part3) 这3个构成一个复合索引

    key_part3 在复合索引里面,,查询的字段也在索引里面,干脆就直接遍历索引查出数据

    思考: 好处,索引存的数据少,数据少页就少,这样可以减少io。

  • ALL

mysql> EXPLAIN SELECT * FROM s1;

一般来说,这些访问方法中除了All这个访问方法外,其余的访问方法都能用到索引,除了index_merge访问方法外,其余的访问方法都最多只能用到一个索引。

小结:

结果值从最好到最坏依次是:

system > const > eq_ref > ref >

fulltext > ref_or_null > index_merge >unique_subquery > index_subquery > range >

index > ALL

SQL 性能优化的目标:至少要达到 range 级别,要求是 ref 级别,最好是 consts级别。(阿里巴巴 开发手册要求)

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/web/1528.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

P2P面试题

1&#xff09;描述一下你的项目流程以及你在项目中的职责&#xff1f; 一个借款产品的发布&#xff0c;投资人购买&#xff0c;借款人还款的一个业务流程&#xff0c;我主要负责测注册&#xff0c;登录&#xff0c;投资理财这三个模块 2&#xff09;你是怎么测试投资模块的&am…

HttpServlet,ServletContext,Listener它仨的故事

1.HttpServlet。 听起来是不是感觉像是个上古词汇&#xff0c;是不是没有阅读下去的兴趣了&#xff1f;Tomcat知道吧&#xff0c;它就是一个servlet容器&#xff0c;当用户向服务器发送一个HTTP请求时&#xff0c;Servlet容器&#xff08;如Tomcat&#xff09;会根据其配置找到…

overflow(溢出)4个属性值,水平/垂直溢出,文字超出显示省略号的详解

你好&#xff0c;我是云桃桃。 一个希望帮助更多朋友快速入门 WEB 前端的程序媛。 云桃桃-大专生&#xff0c;一枚程序媛&#xff0c;感谢关注。回复 “前端基础题”&#xff0c;可免费获得前端基础 100 题汇总&#xff0c;回复 “前端工具”&#xff0c;可获取 Web 开发工具合…

解析 IP(IPv4)地址

IPv 4 地址 一、组成二、IPv4 的分类三、子网掩码四、特殊的地址五、私有 IP 地址六、全局 IP 地址七、私有 IP 地址和全局 IP 地址的关系八、广播地址九、网络地址十、IP 地址个数计算十一、查看电脑的 IP 地址&#xff08;window&#xff09;十二、手动设置电脑的 IP 地址 为…

华为Pura 70系列,一种关于世界之美的可能

1874年&#xff0c;莫奈创作了《印象日出》的油画&#xff0c;在艺术界掀起了一场革命。当时的主流艺术&#xff0c;是追求细节写实&#xff0c;追求场面宏大的学院派。他们称莫奈等人是“印象派”&#xff0c;认为莫奈的画追求光影表达&#xff0c;追求描绘抽象的意境&#xf…

DRF: 序列化器、View、APIView、GenericAPIView、Mixin、ViewSet、ModelViewSet的源码解析

前言&#xff1a;还没有整理&#xff0c;后续有时间再整理&#xff0c;目前只是个人思路&#xff0c;文章较乱。 注意路径匹配的“/” 我们的url里面加了“/”&#xff0c;但是用apifox等非浏览器的工具发起请求时没有加“/”&#xff0c;而且还不是get请求&#xff0c;那么这…

天才简史——Sylvain Calinon

一、研究方向 learning from demonstration&#xff08;LfD&#xff09;领域的专家&#xff0c;机器人红宝书&#xff08;Springer handbook of robotics&#xff09;Robot programming by demonstration章节的合作者。主要研究兴趣包括&#xff1a; 机器人学习、最优控制、几…

[数据结构]——排序——插入排序

目录 ​编辑 1 .插入排序 1.基本思想&#xff1a; 2.直接插入排序&#xff1a; ​编辑 1.代码实现 2.直接插入排序的特性总结&#xff1a; 3.希尔排序( 缩小增量排序 ) 1.预排序 2.预排序代码 3.希尔排序代码 4.希尔排序的特性总结&#xff1a; 1 .插入排序 1.基本思…

从头开始构建自己的 GPT 大型语言模型

图片来源&#xff1a; Tatev Aslanyan 一、说明 我们将使用 PyTorch 从头开始构建生成式 AI、大型语言模型——包括嵌入、位置编码、多头自注意、残差连接、层归一化&#xff0c;Baby GPT 是一个探索性项目&#xff0c;旨在逐步构建类似 GPT 的语言模型。在这个项目中&#xff…

Linux 文件描述符

1、文件描述符 程序和进程的区别&#xff1a; 1、test.c&#xff1a;是一个程序&#xff0c;只占用磁盘空间&#xff0c;不占用内存空间 2、可执行文件 test&#xff1a;是一个程序&#xff0c;只占用磁盘空间&#xff0c;不占用内存空间 3、启动 可执行文件 test&#xff…

强固型工业电脑在码头智能化,龙门吊/流机车载电脑的行业应用

码头智能化行业应用 对码头运营来说&#xff0c;如何优化集装箱从船上到码头堆场到出厂区的各个流程以及达到提高效率。 降低成本的目的&#xff0c;是码头营运获利最重要的议题。为了让集装箱码头客户能够安心使用TOS系统来调度指挥码头上各种吊车、叉车、拖车和人员&#xf…

第一届 _帕鲁杯_ - CTF挑战赛

Mis 签到 题目附件&#xff1a; 27880 30693 25915 21892 38450 23454 39564 23460 21457 36865 112 108 98 99 116 102 33719 21462 21069 27573 102 108 97 103 20851 27880 79 110 101 45 70 111 120 23433 20840 22242 38431 22238 22797 112 108 98 99 116 102 33719 2…

matplotlib从起点出发(15)_Tutorial_15_blitting

0 位图传输技术与快速渲染 Blitting&#xff0c;即位图传输、块传输技术是栅格图形化中的标准技术。在Matplotlib的上下文中&#xff0c;该技术可用于&#xff08;大幅度&#xff09;提高交互式图形的性能。例如&#xff0c;动画和小部件模块在内部使用位图传输。在这里&#…

揭开ChatGPT面纱(3):使用OpenAI进行文本情感分析(embeddings接口)

文章目录 一、embeddings接口解析二、代码实现1.数据集dataset.csv2.代码3.运行结果 openai版本1.6.1 本系列博客源码仓库&#xff1a;gitlab&#xff0c;本博客对应文件夹03 在这一篇博客中我将使用OpenAI的embeddings接口判断21条服装评价是否是好评。 首先来看实现思路&am…

Llama3新一代 Llama模型

最近&#xff0c;Meta 发布了 Llama3 模型&#xff0c;从发布的数据来看&#xff0c;性能已经超越了 Gemini 1.5 和 Claud 3。 Llama 官网说&#xff0c;他们未来是要支持多语言和多模态的&#xff0c;希望那天赶紧到来。 未来 Llama3还将推出一个 400B大模型&#xff0c;目前…

计算机网络——数据链路层(介质访问控制)

计算机网络——数据链路层&#xff08;介质访问控制&#xff09; 介质访问控制静态划分信道动态划分信道ALOHA协议纯ALOHA&#xff08;Pure ALOHA&#xff09;原理特点 分槽ALOHA&#xff08;Slotted ALOHA&#xff09;原理特点 CSMA协议工作流程特点 CSMA-CD 协议工作原理主要…

JVM虚拟机(十二)ParallelGC、CMS、G1垃圾收集器的 GC 日志解析

目录 一、如何开启 GC 日志&#xff1f;二、GC 日志分析2.1 PSPO 日志分析2.2 ParNewCMS 日志分析2.3 G1 日志分析 三、GC 发生的原因3.1 Allocation Failure&#xff1a;新生代空间不足&#xff0c;触发 Minor GC3.2 Metadata GC Threshold&#xff1a;元数据&#xff08;方法…

【数据结构|C语言版】算法效率和复杂度分析

前言1. 算法效率2. 大O的渐进表示法3. 时间复杂度3.1 时间复杂度概念3.2 时间复杂度计算举例 4. 空间复杂度4.1 空间复杂度的概念4.2 空间复杂度计算举例 5. 常见复杂度对比结语 ↓ 个人主页&#xff1a;C_GUIQU 个人专栏&#xff1a;【数据结构&#xff08;C语言版&#xff09…

Kafka源码分析(四) - Server端-请求处理框架

系列文章目录 Kafka源码分析-目录 一. 总体结构 先给一张概览图&#xff1a; 服务端请求处理过程涉及到两个模块&#xff1a;kafka.network和kafka.server。 1.1 kafka.network 该包是kafka底层模块&#xff0c;提供了服务端NIO通信能力基础。 有4个核心类&#xff1a;…

【Django】django.core.exceptions.AppRegistryNotReady: Apps aren‘t loaded yet.

其中django后台manage.py入口程序报错&#xff0c;检索很多问题解决方案&#xff0c;这里记录下个人问题原因 1.django启动异常问题详情 django.core.exceptions.AppRegistryNotReady: Apps aren’t loaded yet. 2.问题原因 Python第三方包安装版本不一致或缺少依赖包&…