MySQL优化Explain命令简介(一)
最近碰到MySQL需要写入大量数据并查询的场景,于是学习了一下MySQL的查询优化,想找关于explain命令的详细资料,然而网上并没有找全,最后终于在《高性能MySQL》中找到了对这一命令的详细介绍,以下摘录出来记录一下。
EXPLAIN的用法很简单,将其加入SELECT 关键字前面即可,MySQL将会对这条查询做个特殊标记,实际执行时会将其执行计划中具体执行的每一步的相关信息反馈回来,一个步骤占一行。
一个简单的EXPLAIN执行结果:
+----+-------------+-------+------+---------------+------+---------+------+------+----------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+-------+------+---------------+------+---------+------+------+----------------+
| 1 | SIMPLE | NULL | NULL | NULL | NULL | NULL | NULL | NULL | No tables used |
+----+-------------+-------+------+---------------+------+---------+------+------+----------------+
查询中的每个table都将有一行记录描述其相关信息,这个table是一个广义的概念,一个子查询、一个UNION结果属于其定义范围。
EXPLAIN会实际执行吗?
记住EXPLAIN只是一个sql执行的模拟近似,有时候能真实反应sql实际执行的步骤和实际情况,然而有时候也可能和实际执行情况相差甚远。
下面是EXPLAIN的几个无能为力的情况:
- EXPLAIN不会分析关于触发器、存储函数(stored function?)或者自定义函数会如何影响实际查询。
- EXPLAIN对存储过程无效,当然你可以将其具体语句抽取出来,单独执行EXPLAIN
- EXPLAIN不会显示查询执行过程中做的特定的优化
- EXPLAIN并不会显示关于查询执行计划的所有相关信息(MYSQL开发人员一直在尝试增加进尽可能多的相关信息)
- EXPLAIN并不会区分一些同名但实际有差别的概念。比如“filesort”同时用于描述内存排序和临时文件,对于硬盘和内存中的临时表也都使用“temporary”表示。
- EXPLAIN有时可能反而具有误导性。例如它会对一个很小的limit查询显示会进行全索引扫描(MYSQL5.1的EXPLAIN会展示更加精确的相关信息)
重写Non-SELECT查询
MYSQL EXPLAIN只能分析SELECT查询,无法分析存储过程、INSERT/UPDATE/DELET或者其他语句。用户可以通过将其转化为等效的的SELECT语句,将其中访问到的所有列表都放入SELECT字段、join或者WHERE条件中去。
EXPLAIN中的列字段
EXPLAIN的输出总是相同的列字段和格式(EXPLAIN EXTENDED增加了filtered列字段,EXPLAIN PARTITIONS增加了partions列字段),而其行数和具体值内容则会根据具体语句变化。接下来我们将为读者解释一个具体EXPLAIN执行结果的每列字段的具体含义。注意输出结果中的行顺序反映了MYSQL实际执行查询语句中各部分的顺序,这个顺序不一定和原始SQL语句中看到的顺序相同。
id列
这一列总是一个数字,用于标识SELECT所属的行,如果原始语句中没有任何子查询或union,就只有一个SELECT,该列的每一行都将显示1,否则,内部的SELECT语句通常会根据他们在原始语句中的顺序递增标号。
MYSQL将SELECT查询分为简单(simple)和(complex)类型,complex类型则进一步分为三组:简单子查询(simple subqueris),所谓的派生表查询(FROM子句中的子查询)和联合(UNIONS)查询。下面是一个简单的子查询:
FROM子句和UNIONS中的子查询会增加id列的复杂度,以下是一个FROM 子句中有简单子查询的语句:
这个查询会产生一个匿名的临时表,MYSQL内部通过临时表的别名(der)在外层查询中引用它,在之后讲解的更复杂的查询语句EXPLAIN的ref列中将能看到实际的例子。
最后,下面是一个联合(UNION)查询:
注意UNION结果输出的额外那行,UNION结果总是被放入一个匿名临时表中,然后MYSQL从其中都会查询结果,这个临时表并不会出现在原始的SQL中,所以它的id是NULL。相比之前的例子(FROM子句中的一个子查询),这个UNION结果的临时表被放在了结果中的最后一行,而不是首行。
目前为止的例子都非常简单直接,不过下面将这三类语句混合使用后,我们将可以产生更加复杂的分析结果。
select_type列
select_type显示该行代表的查询是简单查询和复杂查询(如果是复杂查询,进一步细分为三种复杂查询中的一种)。值SIMPLE标识该查询不包含任何子查询与联合查询UNIONS,如果查询语句包含任何复杂查询类型,最外层的查询部分被标为PRIMARY,其他部分则分为如下情况:
子查询(SUBQUERY)
包含在SELECT部分嵌套SELECT语句(即不再FROM子句中)会被标为SUBQUERY
派生(DERIVED)
包含在FROM子句中的子查询被标识为DERIVED,MYSQL会递归执行这类查询并放入临时表中。MYSLQ内部通过“derived table”引用这张临时表,因为这张临时表派生自子查询。
联合(UNION)
UNION语句中的第二个和后续SELECTS会被标为UNION,第一个SELECT则被视为作为外层查询执行,会被标识为PRIMARY,如果UNION被包含在一个子查询中执行,第一个SELECT则会被标识为DERIVED。
联合结果(UNION RESULT)
这个SELECT用于从UNION执行产生的匿名临时表中检索结果,因而被标识为UNION SELECT。
除了这些值,SUBQUERY和UNION也可能被标识为DEPENDENT和UNCACHEABLE。DEPENDENT表示SELECT依赖于外层查询中的某些数据;UNCACHEABLE则表示SELECT中的某些部分会阻止结果被Item_cache缓存(Item_cahe并没有被文档正式记录,它和query cache不是一个东西,尽管它也会因为一些同样的原因而无法使用,比如RAND()函数)
table列
table列标识对应行访问的是哪一张表,一般就是sql中显式使用的表名或其别名。
可以通过从上到下观察到join optimizer为一般查询优化过后join操作的实际执行次序。比如下例:
派生表与联合
如果在FROM子句中存在子查询或者UNION操作,table列就变得起来了。因为在这些情况下MYSQL会创建仅在查询执行期间存在的匿名临时表,所以实际上并没有真正的“表”可以被这一列引用。
对于FROM子句中的子查询,table列的值是<derivedN>的形式,N代表子查询的id,总是执行EXPLAIN输出中后面的某一行。
而当有UNION操作时,其联合结果 table列包含一系列参与UNION操作的id,这些id总是执行EXPLAIN结果中该行前面的某些行,因为UNION操作总是会在所有参与UNION的子查询执行完之后才会真正执行。如果有超过20个id参与了UNION操作,table列可能会被截断以防止结果太长,所以会看不到全部id列表,不过其实第一个id到UNION RESULt行之间的所有行,就是参与UNION操作的所有子查询。
一个复杂的SELECT类型
下面是一个没有实际意义的复杂select查询,仅仅作为一个说明例子:
LIMIT语句是为了方便不使用EXPLAIN语句直接执行时查看结果,上面语句对应的EXPLAIN结果如下:
让我们从上到下仔细分析一下这个结果:
- 第一行前向引用了der_1,即标识的<derived3>,这一行来源于原始SQL中的line2
- 第二行的id是3,这是因为它是第三个SELECT查询的一部分,由于它嵌套于FROM子句中的一个子查询中,它被标识为DERIVED,这一行来源于line6和line7
- 第三行的id是2,它来源于line3,注意这一行位于第二行之后,表明它应该之后执行。正如其select_type的值DEPENDENT SUBQUERY所示,它依赖于一个外层查询的结果(关联子查询,correlated subquery),这个case中的外层子查询正是line2中从der_1检索数据的SELECT。
- 第四列值为UNION,标识其是UNION查询中后面的部分,table是<derived6>,意味着它是从一个FROM子句中的子查询检索数据并将生成一个临时表加入到UNION中,和之前一样,未了找到这个子查询对应的行结果,必须往其之后看。
- 第五列是der_2的子查询,对应line13,line14和line15,正是第五行中引用的<derived6>
- 第六行是一个<derived6>中的普通子查询,id是7,这一点很重要
- 因为id7>5,意味着<derived6>子查询的边界,当EXPLAIN输出select_type为DERIVED的一行的时候,它标识一个嵌套作用域的起始。如果后面行中子查询的id更小,意味着嵌套域已经被关闭了。我们知道第七行是从<derived6>中检索数据的SELECT查询的一部分,即第四个SELECT查询的一部分(line11),这个例子并不需要知道嵌套作用域的意义和规则也可以简单理解,但有时就比这个复杂了。另一个需要注意的点是第七行中的select type值为UNCACHEABLE SUBQUERY,这是用户变量使用引起的。
- 最后一行是UNION RESULt,代表从UNION的临时表中读取数据的阶段,这一行返回id为1和4的查询结果,即<derivied3>和<derived6>的结果。
正如你看到的,这些复杂的SELECT组合会导致EXPLAIN结果难以分析和理解,需要熟悉规则并多加练习。
理解EXPLAIN结果的时候,需要上下来回观察、分析。上例中,如果仅看第一行的话,根本不会知道其是UNION的一个部分,只有看到最后一行才会发现这一情况。
MySQL优化Explain命令简介(一)的更多相关文章
- MySQL优化Explain命令简介(二)
type列 MySQL手册上注明type列用于描述join type,不过我们认为把这一列视为对access type--即MySQL决定如何在表中寻找数据的方式的描述,更加合适一些,以下所示从最坏情 ...
- 一次浴火重生的MySQL优化(EXPLAIN命令详解)
一直对SQL优化的技能心存无限的向往,之前面试的时候有很多面试官都会来一句,你会优化吗?我说我不太会,这时可能很多人就会有点儿说法了,比如会说不要使用通配符*去检索表.给常常使用的列建立索引.还有创建 ...
- mysql优化——explain详解
MySQL的EXPLAIN命令用于SQL语句的查询执行计划(QEP).这条命令的输出结果能够让我们了解MySQL 优化器是如何执行SQL 语句的.这条命令并没有提供任何调整建议,但它能够提供重要的信息 ...
- MySQL的EXPLAIN命令用于SQL语句的查询执行计划
MySQL的EXPLAIN命令用于SQL语句的查询执行计划(QEP).这条命令的输出结果能够让我们了解MySQL 优化器是如何执行SQL 语句的.这条命令并没有提供任何调整建议,但它能够提供重要的信息 ...
- MySQL 查询性能优化 - EXPLAIN 命令
查询优化的官方文档在 这里. EXPLAIN 的输出格式 译文 1. MySQL 架构 1.1 MySQL 的简化架构 MySQL 可以简单的分为三层:连接层.服务层.存储引擎层.其中服务层包含了 M ...
- MySQL的Explain命令
Explain命令是查看查询优化器如何决定执行查询的主要办法. 调用 EXPLAIN 要使用EXPLAIN,只需在查询中的SELECT关键字之前增加EXPLAIN.MySQL会在查询上设置一个 ...
- mysql优化:explain分析sql语句执行效率
Explain命令在解决数据库性能上是第一推荐使用命令,大部分的性能问题可以通过此命令来简单的解决,Explain可以用来查看SQL语句的执行效 果,可以帮助选择更好的索引和优化查询语句,写出更好的优 ...
- 【MySQL】EXPLAIN命令详解
具体参考: https://www.cnblogs.com/gomysql/p/3720123.html 原文如下: 在工作中,我们用于捕捉性能问题最常用的就是打开慢查询,定位执行效率差的SQL,那么 ...
- mysql优化–explain分析sql语句执行效率
Explain命令在解决数据库性能上是第一推荐使用命令,大部分的性能问题可以通过此命令来简单的解决,Explain可以用来查看SQL语句的执行效 果,可以帮助选择更好的索引和优化查询语句,写出更好的优 ...
随机推荐
- java多态-向上转型和向下转型
向上转型:符合“is a”,是安全的,子类向上到父类,多余的属性和方法会丢弃 向下转型:不安全的,用instanceof提前判断一下,以免抛出异常 instanceof用法: result = obj ...
- Postgresql 数据库,如何进行数据备份以及导入到另外的数据库
方法其实有很多种,这里用的方法比较稳妥.之后有时间会补充别的方法. 该方法分为三步:备份数据,新建表结构,导入数据 备份数据:>>\copy table_name to '/home/ba ...
- Ubunru 16.04 kinetic 下安装turtlebot2
默认安装Ubuntu16.04以及ROS kinetic 防止忘记. 1. 准备工作: $ sudo apt-get install python-rosdep python-wstool ros-k ...
- Angular动态表单生成(一)
好久不写博客了,手都生了,趁着最近老大让我研究动态表单生成的时机,撸一发博客~~ 开源项目比较 老大丢给我了两个比较不错的开源的动态表单生成工具,这两个项目在github上的star数量基本持平: h ...
- 更换php工具箱出现问题 CI框架的问题 【问题解决】
2018/10/08 09:56:47 [error] 8472#8588: *1 FastCGI sent in stderr: "PHP Warning: Unknown: open_ ...
- Failed to read artifact descriptor for org.apache.maven.plugins:maven-jar-plugin
在更新maven项目的时候出现许多jar包找不到的问题,但是在本地仓库中查找的时候包含这些jar包. 解决办法: 把所有报错缺少的jar包所在的文件夹删掉,重新更新maven项目,重新下载完成后错误解 ...
- spring,springMVC,mybatis项目添加maven后报500错
<resources> <resource> <directory>src/main/java</directory> <includes> ...
- ES6读书笔记(二)
前言 前段时间整理了ES6的读书笔记:<ES6读书笔记(一)>,现在为第二篇,本篇内容包括: 一.数组扩展 二.对象扩展 三.函数扩展 四.Set和Map数据结构 五.Reflect 本文 ...
- [iOS]UIFont的lineHeight与pointSize
写这篇文章的初衷是由于我有一次想获取一个font的字体大小时使用了UIFont的lineHeight属性,结果是比字体的大小要大了一部分,然后经过查阅各种资料,发现了原因. 首先我们来看一看UIFon ...
- jar下载地址
java开发难免需要下载额外的jar,推荐一个地址 http://www.java2s.com/Code/Jar/CatalogJar.htm