什么是MySQL的执行计划(Explain关键字)?
什么是Explain
Explain被称为执行计划,在语句之前增加 explain 关键字,MySQL 会在查询上设置一个标记,模拟MySQL优化器来执行SQL语句,执行查询时,会返回执行计划的信息,并不执行这条SQL。(注意,如果 from 中包含子查询,仍会执行该子查询,将结果放入临时表中)。
Explain可以用来分析SQL语句和表结构的性能瓶颈。通过explain的结果,可以了解到如数据表的查询顺序、数据查询操作的操作类型、哪些索引可以被命中、哪些索引实际会命中、每个数据表有多少行记录被查询等信息。
Explain命令扩展
explain extended
在explain的基础上提供一些额外的查询信息,在explian extended执行以后,通过show warnings命令可以得到优化后的查询语句,可以看出优化器做了哪些工作,还可以通过某些数据估算表连接的行数。
explain partitions
用于分析使用了分区的表,会显示出可能用到的分区。
两点重要提示
1. Explain结果是基于数据表中现有数据的。
2. Explain结果与MySQL版本有很大的关系,不同版本的优化器的优化策略不同。
本文示例使用的数据库表
Explain命令(关键字)
explain简单示例
mysql>explain select * from t_user;
在查询中的每个”表”会输出一行,这里的“表”的意义非常广泛,不仅仅是数据库表,还可以是子查询、一个union 结果等。
explain结果列说明
【id列】
id列是一个有顺序的编号,是查询的顺序号,有几个 select 就显示几行。id的顺序是按 select 出现的顺序增长的。id列的值越大执行优先级越高越先执行,id列的值相同则从上往下执行,id列的值为NULL最后执行。
【select_type列】
select_type列的值标明查询的类型:
1)simple:表明当前行对应的select是简单查询,不包含子查询和union
2)primary:表明当前行对应的select是复杂查询中最外层的 select
3)subquery:表明当前行对应的select是包含在 select 中的子查询(不在 from 子句中)
4)derived:表明当前行对应的select是包含在 from 子句中的子查询。
MySQL会创建一个临时表来存放子查询的查询结果。用如下的语句示例说明:
explain select (select 1 fromt_user where user_id=1) from (select * from t_group where group_id=1) tmp;
*注意,在资料收集过程中,发现不同版本的MySQL表现不一致,经反复对比,5.7及以后版本的输出如下:
很显然,MySQL在这方面进行了优化.
*注意,MySQL不同版本Explain表现差异很大,有些场景,从语句层面看,是要使用到索引,但经过优化器分析,结合表中现有数据,如果MySQL认为全表扫描性能更优,则会使用全表扫描。
5)union:表明当前行对应的select是在 union 中的第二个和随后的 select
6)union result:表明当前行对应的select是从 union 临时表检索结果的 select
explain select 1 union all select 2 fromdual;
MySQL5.7及以后同样做了优化
【table列】
table列的结果表明当前行对应的select正在访问哪个表。当查询的<from>子句中有子查询时,table列是 <derivedN> 格式,表示当前的select依赖 id=N结果行对应的查询,要先执行 id序号=N 的查询。当存在 union 时,UNION RESULT 的 table 列的值为<unionN1,N2>,N1和N2表示参与 union 的select 行的id序号。
【type列】
type列的结果表明当前行对应的select的关联类型或访问类型,也就是优化器决定怎么查找数据表中的行,以及查找数据行记录的大概范围。该列的取值优化程度的优劣,从最优到最差依次为:null>system> const > eq_ref > ref > range > index > ALL。一般来说,要保证查询达到range级别,最好达到ref。
1)null,MySQL优化器在优化阶段分解查询语句,在优化过程中就已经可以得到结果,那么在执行阶段就不用再访问表或索引。
explain select min(user_id) from t_user;
这时的函数min,在索引列user_id中选取最小值,可以直接查找索引来完成,不需要执行时再访问数据表。
2)const和system:const出现在用 primary key(主键) 或 unique key(唯一键) 的所有列与常数比较时,优化器对查询进行优化并将其部分查询转化成一个常量。最多有一个匹配行,读取1次,速度非常快。而system是const的特例,表中数据只有一条匹配时为system。此时可以用explain extended+show warnings查看执行结果。
explain extended select * from (select * from t_user where user_id = 1) tmp
show warnings;
MySQL5.7及以后版本优化后:
3)eq_ref:primary key(主键)或 unique key(唯一键) 索引的所有构成部分被join使用 ,只会返回一条符合条件的数据行。这是仅次于const的连接类型。
explain select * from t_group_user gu left join t_group g ong.group_id = gu.group_id;
4) ref:与eq_ref相比,ref类型不是使用primary key(主键) 或 unique key(唯一键)等唯一索引,而是使用普通索引或者联合唯一性索引的部分前缀,索引和某个值相比较,可能会找到符合条件的多个数据行。
1. 如下示例,使用的group_name是普通索引
explain select * from t_group where group_name= 'group1';
2.关联表查询
explain select g.group_id from t_group gleft join t_group_user gu on gu.group_id = g.group_id;
5)range:出现在 in(),between ,> ,<, >= 等操作符中。使用一个索引来查询给定范围的行。
6)index:扫描全表索引(index是从索引中读取的,所有字段都有索引,而all是从硬盘中读取),比ALL要快。
explain select * from t_group;
7)all:即全表扫描,需要从头到尾去查找所需要的行。一般这种情况下这需要增加索引来进行查询优化了
explain select * from t_user;
【possible_keys列】
这一列的结果表明查询可能使用到哪些索引。但有些时候也会出现出现possible_keys 列有结果,而 后面的key列显示 null 的情况,这是因为此时表中数据不多,优化器认为查询索引对查询帮助不大,所以没有走索引查询而是进行了全表扫描。
如果possible_keys列的结果是null,则表明没有相关的索引。这时,可以通过优化where子句,增加恰当的索引来提升查询性能。
【key列】
这一列表明优化器实际采用哪个索引来优化对该表的访问。如果没有使用索引,则该列是 null。
【key_len列】
这一列表明了在索引里使用的字节数,通过这个值可以大致估算出具体使用了联合索引中的前几个列。
key_len计算规则这里不再赘述,不同的数据类型所占的字节数是不一致的。
【ref列】
这一列表明了在key列记录的索引中,表查找值所用到的列或常量,常见的有:const(常量),字段名,如user.user_id
【rows列】
这一列表明优化器大概要读取并检测的行数。跟实际的数据行数大部分情况是不一致的。
【Extra列】
顾名思义,这一列表明的是额外信息,这一列的取值对优化SQL非常有参考意义。常见的重要取值如下:
1)using index:所有被查询的字段都是索引列(称为覆盖索引),并且where条件是索引的前导列,出现这样的结果,是性能高的表现。
explainselect group_id,group_name from t_group;
2)using where:被查询的列未被索引覆盖,where条件也并非索引的前导列,表示 MySQL 执行器从存储引擎接收到查询数据,再进行“后过滤”(Post-filter)。所谓“后过滤”,就是先读取整行数据,再检查此行是否符合 where 句的条件,符合就留下,不符合便丢弃。
explain select * from t_user whereuser_name='user1';
3)using where Using index:被查询的列被索引覆盖,并且where条件是索引列之一但是不是索引的前导列,也就是没有办法直接通过索引来查询到符合条件的数据
explain select * from t_group where group_name = 'group1';
4)null:被查询的列没有被索引覆盖,但where条件是索引的前导列,此时用到了索引,但是部分列未被索引覆盖,必须通过“回表查询”来实现,不是纯粹地用到了索引,也不是完全没用到索引
explain select * from t_user where user_id='1';
5)using index condition:与using where类似,查询的列不完全被索引覆盖,where条件中是一个前导列的范围;这种情况未能通过示例显现,可能跟MySQL版本有关系。
6) using temporary:这表明需要通过创建临时表来处理查询。出现这种情况一般是要进行优化的,用索引来优化。创建临时表的情况:distinct,group by,orderby,子查询等
explain select distinct user_name from t_user;
explain select distinct group_name fromt_group; --group_name是索引列
7) usingfilesort:在使用order by的情况下出现,mysql会对结果使用一个外部索引排序,而不是按索引次序从表里读取行。此时mysql会根据连接类型浏览所有符合条件的记录,并保存排序关键字和行指针,然后排序关键字并按顺序检索行信息。这种情况下要考虑使用索引来优化的。
explain select * from t_user orderby user_name;
explain select * from t_group order bygroup_name; --group_name是索引列
查询优化建议
结合前面的描述,首先看 type列的结果,如果有类型是 all 时,表示预计会进行全表扫描(fulltable scan)。通常全表扫描的代价是比较大的,建议创建适当的索引,通过索引检索避免全表扫描。
再来看下 Extra 列的结果,如果有出现 Using temporary 或者 Using filesort 则要多加关注:
Using temporary,表示需要创建临时表以满足需求,通常是因为GROUP BY的列没有索引,或者GROUP BY和ORDER BY的列不一样,也需要创建临时表,建议添加适当的索引。
Using filesort,表示无法利用索引完成排序,也有可能是因为多表连接时,排序字段不是驱动表中的字段,因此也没办法利用索引完成排序,建议添加适当的索引。
Using where,通常是因为全表扫描或全索引扫描时(type 列显示为 ALL 或index),又加上了WHERE条件,建议添加适当的索引。
索引使用情况分析
数据库表
主键索引:demo_id
联合索引:c1,c2,c3
实例说明
实例一:
explain select * from t_demo where c1='d1'and c2='d2' and c3='d3';
explain select * from t_demo where c2='d2'and c1='d1' and c3='d3';
explain select * from t_demo where c3='d3'and c1='d1' and c2='d3';
几个Sql表现一致
type=ref,ref=const,const,const
执行常量等值查询时,改变索引列的顺序并不会更改explain的执行结果,优化器会进行优化,推荐按照索引顺序列编写sql语句。
实例二:
explain select * from t_demo where c1='d1'and c2>'d2' and c3='d3';
explain select * from t_demo where c1='d1'and c3>'d3' and c2='d2';
第一个例子范围右侧索引失效,使用到了两个索引。
第二个例子,由于优化器优化的原因,使用到了全部的三个索引。
实例三:
explain select * from t_demo wherec1>'c' and c2='d2' and c3='d3';
explain select * from t_demo wherec1>'e' and c2='d2' and c3='d3';
从上面两个实例可以发现,同样使用最左的索引列范围查询,有些情况未用到索引,做了全表扫描(第一个例子);有些情况使用到了索引(第二个例子)。
经反复验证,发现如下规律(不一定可靠),也可能与数据的第一行或最小值相关。
1. 跟存储的数据有关
2. 在大于条件下,如果条件数据小于列数据,则索引无效;如果条件数据大于列数据,则索引有效;
在设计查询条件时,请注意规避。
针对第一个例子,可以采用覆盖索引的方式优化。
实例四:
explain select * from t_demo where c1='d1'and c2='d2' order by c3;
explain select * from t_demo where c1='d1'order by c3;
explain select * from t_demo where c1='d1'and c3='d3' order by c2;
order by排序使用到索引和没使用到索引的情况
实例五:
explain select * from t_demo where c1='d1'and c4='d4' order by c1,c2;
条件列包含没有索引的列,出现了Using filesort
实例六:
explain select * from t_demo where c1='d1'and c4='d4' group by c1,c2;
性能非常差的场景,同时出现了Using temporary和Using filesort
总结
1. 两种方式的排序filesort和index,Usingindex是指MySQL扫描索引本身完成排序。index效率高,filesort效率低。
2. order by满足两种情况会使用Using index。
1)order by语句使用索引最左前列。
2)使用where子句与order by子句条件列组合满足索引最左前列。
3. 尽量在索引列上完成排序,遵循索引建立(索引创建的顺序)时的最佳左前缀法则。
4. group by与order by很类似,都是先排序后分组,遵照索引创建顺序的最佳左前缀法则。
相关文章:

什么是MySQL的执行计划(Explain关键字)?
什么是Explain Explain被称为执行计划,在语句之前增加 explain 关键字,MySQL 会在查询上设置一个标记,模拟MySQL优化器来执行SQL语句,执行查询时,会返回执行计划的信息,并不执行这条SQL。(注意&…...

编码格式科普ASCII unicode utf-8 usc-2 GB2312
1.ASCII(标准版) 可以表示所有英文字符(包括大写和小写)和数字,长度为7bit,最多可以表示0-127 个值,2的7次方个数字。比如比如“a” 对照ASCII码的值为97(十进制)或11000…...

Pycharm中新建一个文件夹下__init__.py文件有什么用
在PyCharm中新建一个文件夹下的__init__.py文件有以下几个作用: 声明文件夹为一个Python包:__init__.py文件的存在告诉Python解释器该文件夹是一个Python包。当你导入该文件夹下的模块时,Python会将其视为一个包而不是普通的文件夹。这允许你…...

OracleBulkCopy c#批量插入oracle数据库的方法
datatable中的数据 存入oracle表中,要求 二者字段名一致,如果不一致,通过这个实现对应: bulkCopy.ColumnMappings.Add("SERVNUMBER", "SN"); 首先要引入Oracle.DataAccess.dll文件(在oracle客户端…...

046_第三代软件开发-虚拟屏幕键盘
第三代软件开发-虚拟屏幕键盘 文章目录 第三代软件开发-虚拟屏幕键盘项目介绍虚拟屏幕键盘 关键字: Qt、 Qml、 虚拟键盘、 qtvirtualkeyboard、 自定义 项目介绍 欢迎来到我们的 QML & C 项目!这个项目结合了 QML(Qt Meta-Object L…...

MySQL主从搭建,实现读写分离(基于docker)
一 主从配置原理 mysql主从配置的流程大体如图: 1)master会将变动记录到二进制日志里面; 2)master有一个I/O线程将二进制日志发送到slave; 3) slave有一个I/O线程把master发送的二进制写入到relay日志里面; 4…...

uni-app android picker选择默认月份
微信小程序选中月份后下次再点开是上次的选中的月份,而编译的android应用只默认当前月份 <picker mode"date" ref"picker" :disabled"disabled" :value"date" fields"month" change"bindDateChange&quo…...

Go 接口-契约介绍
Go 接口-契约介绍 文章目录 Go 接口-契约介绍一、接口基本介绍1.1 接口类型介绍1.2 为什么要使用接口1.3 面向接口编程1.4 接口的定义 二、空接口2.1 空接口的定义2.2 空接口的应用2.2.1 空接口作为函数的参数2.2.2 空接口作为map的值 2.3 接口类型变量2.4 类型断言 三、尽量定…...

变压器试验VR虚拟仿真操作培训提升受训者技能水平
VR电气设备安装模拟仿真实训系统是一种利用虚拟现实技术来模拟电气设备安装过程的培训系统。它能够为学员提供一个真实、安全、高效的学习环境,帮助他们更好地掌握电气设备的安装技能。 华锐视点采用VR虚拟现实技术、MR混合现实技术、虚拟仿真技术、三维建模技术、人…...

Mastering Makefile:模块化编程技巧与经验分享
在Linux项目管理中,Makefile是一个强大的工具,它可以帮助我们自动化编译和测试过程。然而,随着项目的增长,Makefile可能会变得越来越复杂,难以管理。在这篇文章中,我将分享一些模块化编程的技巧和经验&…...

el-input输入校验插件(正则表达式)
使用方法:在main.js文件中注册插件然后直接在<el-input>加入‘v-插件名’ (1)在main.js文件: // 只能输入数字指令 import onlyNumber from /directive/only-number; Vue.use(onlyNumber); (2)在src/directive文件夹中 &a…...

【Matplotlib】plt.plot() X轴横坐标展示完整整数坐标
比如说,我的数据应该是 x轴从2到21的20个整数 y轴对应值 但是直接plot的话x轴显示居然有小数点什么鬼 可以这样改...

左手 Jira,右手 Polarion,驶入互联网和制造业十字路口的新能源汽车
笔者之前一直在互联网公司从事软件研发,创立 Bytebase 之后,才开始接触到各行各业的用户。最近来自汽车行业的客户不少,所以就翻翻相关资料。周末微信收到了一条推送,提到汽车行业的软件研发管理,也由此了解到了 Polar…...

网络安全(黑客)-0基础小白自学
1.网络安全是什么 网络安全可以基于攻击和防御视角来分类,我们经常听到的 “红队”、“渗透测试” 等就是研究攻击技术,而“蓝队”、“安全运营”、“安全运维”则研究防御技术。 2.网络安全市场 一、是市场需求量高; 二、则是发展相对成熟…...

ActiveMQ、RabbitMQ、RocketMQ、Kafka介绍
一、消息中间件的使用场景 消息中间件的使用场景总结就是六个字:解耦、异步、削峰 1.解耦 如果我方系统A要与三方B系统进行数据对接,推送系统人员信息,通常我们会使用接口开发来进行。但是如果运维期间B系统进行了调整,或者推送过…...

unity打AB包,AssetBundle预制体与图集(二)
第二步:加载AB包的资源,用于显示 using System.Collections; using System.Collections.Generic; using System.IO; using UnityEngine; using UnityEngine.Networking; using UnityEngine.U2D; using UnityEngine.UI;public class GameLaunch : MonoBe…...

【网络安全 --- web服务器解析漏洞】IIS,Apache,Nginx中间件常见解析漏洞
一,工具及环境准备 以下都是超详细保姆级安装教程,缺什么安装什么即可(提供镜像工具资源) 1-1 VMware 16.0 安装 【网络安全 --- 工具安装】VMware 16.0 详细安装过程(提供资源)-CSDN博客文章浏览阅读20…...

Python基础——注释、缩进、语法、标识符、关键字
注释 Python中单行注释用#表示,多行注释由3对双引号或单引号包裹:可以使用快捷键CTRLR进行注释 # 我是单行注释"""我是多行注释 """缩进 python使用“缩进”即一行代码前的空白区域确定代码之间的逻辑关系和层次关系。…...

排序算法的分析及实现
目录 1. 排序 1.1. 排序的概念 1.2. 排序的稳定性 1.3. 内部排序和外部排序 2. 直接插入排序 2.1. 直接插入排序 2.2. 直接插入排序的两种情况 1. 情况一 2. 情况二 2.3. 直接插入排序的单趟排序 2.4. 直接插入排序的完整实现 2.5. 直接插入排序的时…...

rancher或者其他容器平台使用非root用户启动jar
场景: java程序打成镜像,在rancher上运行,默认是root账户,发现hdfs或者hive不允许root账户操作;所以打算用费root账户启动jar,使其具有hive和hdfs的操作权限。 Dockerfile entrypoint.sh 思路就是上面这样…...

Scrapy使用和学习笔记
前言 Scrapy是非常优秀的一个爬虫框架,基于twisted异步编程框架。yield的使用如此美妙。基于调度器,下载器可以对scrapy扩展编程。插件也是非常丰富,和Selenium,PlayWright集成也比较轻松。 当然,对网页中的ajax请求…...

<sa8650> sa8650介绍
一、sa8650 描述 设备说明 QAM8650P/QAMSRV1H是高通公司的下一代Snapdragon高级驾驶员辅助系统(ADAS)模块,旨在实现卓越的性能和电源效率。 它已被开发为SEooC(上下文之外的安全元素),针对假定的ASIL B用例*。QAM8650P/QAMSRV1H模块的关键组件包括SA8650P/SRV1H SoC、PM…...

[架构之路-244]:目标系统 - 设计方法 - 软件工程 - 软件开发方法:结构化、面向对象、面向服务、面向组件的开发方法
目录 前言: 一、概述: 软件聚合的程度由简单到复杂 二、主要开发方法详见 2.1 结构化的开发方法 2.2 面对对象的开发方法 2.3 面向服务的开发方法 2.4 面向组件的开发方法 三、不同开发方法比较 3.1 结构化开发方法 3.2 面向对象(OOP)开发方法 3.3 面向服…...

Qt窗体自动销毁
Qt中通过对象树的方式,实现了窗体自动析构,只要我们使用得当,就能免去自己去释放窗体对象的内存,但是我们得清楚Qt窗体自动析构的机制,什么情况下能够自动析构,什么情况不能。操作不当的情况可能造成内存泄…...

制造业企业设备管理常见的三个问题及对应的解决方案
当今的市场如同茫茫大海,既充满机遇,也伴随着波动的风险。在现代制造业中,企业常常面临着各种挑战,这些挑战可能妨碍其发展和竞争力。但制造企业往往具备能够解决挑战的能力,借助软件工具的力量,可以更好地…...

linux文件目录
/bin 二进制可执行命令。该目录下存放着普通用户的命令 /boot 启动Linux的核心文件 /data 用户用于存放日志等数据的目录 /dev 系统的设备文件,即设备的驱动程序 /etc 系统所有的配置文件都在这个目录中 /home 用户主目录的基点 /lib 存放着和…...

流量卡是什么?流量卡为什么有虚量,51物联卡带你全面了解一下。
上个月在网上买了一张流量卡,用了之后才发现剩余流量和套餐不符,这种流量是虚的吗?还有必要接着使用吗?这是一个网友跟小编私信咨询的一个问题。 其实流量卡流量和套餐不符,这个问题是比较常见的一个问题ÿ…...

浅谈电力物联网时代物联网技术在电力系统中的应用
贾丽丽 安科瑞电气股份有限公司 上海嘉定201801 摘要:在电力系统建设中,物联网的应用不仅促进了我国电力工业的发展,而且对我国的物联网技术也起到了一定的促进作用。随着物联网技术应用于电力系统,推动了中国工业的快速发展。因…...

HTTP 状态代码 (Winhttp.h)
文章目录 对开发者有什么帮助状态码产生要求WinHTTP状态码推荐阅读 Microsoft Windows HTTP Services (WinHTTP) 的用户应使用最新版本的技术版本 5.1。 版本 5.0 不再受支持。 对开发者有什么帮助 HTTP状态代码(HTTP status codes)是Web开发中的标准返…...

开槌在即:陈可之油画|《赞红梅》
《赞红梅》 尺寸:38x30cm 陈可之2020年绘 “墙角数枝梅,凌寒独自开。遥知不是雪,为有暗香来。”梅花,迎雪吐艳,严寒飘香,被视为坚忍不拔、自强不息等精神品质的象征物。文学艺术史上,有众多以“…...