mysql explain命令是查询性能优化不可缺少的一部分。

explain output columns

列名 说明
id 执行编号,标识select所属的行。如果在语句中没有子查询或者关联查询,只有唯一的select,每行都将显示1。否则,内层的select语句一般会顺序编号,对应于其在原始语句中的位置
select_type 显示本行是简单或是复杂select。如果查询有任何复杂的子查询,则最外层标记为primary(derived、Union、Union resuit)
table 访问引用哪个表(引用某个查询,如“derived3”)
partitions 匹配的分区
type 数据访问/读取操作类型(all、index、range、ref、eq_ref、const/system、NULL)。join类型
possible_keys 揭示哪一些索引可能有利于高效的查找
key 此次查询中确切使用到的索引.
key_len 显示mysql在索引里使用的字节数
ref 哪个字段或常数与key一起被使用
rows 为了找到所需的列而需要读取的行数,估算值,不精确。通过把所有rows列值相乘,可粗略估算整个查询会检查的行数
filtered 表示此查询条件所过滤的数据的百分比
Extra 额外信息,如using index、filesort等

id

id是用来顺序标识整个查询中select语句的,在嵌套查询中id越大的语句越先执行。该值可能为null,说明这一行用来表示其他行的联合查询结果。

select_type

select_type 表示了查询的类型, 它的常用取值有:

  • SIMPLE,表示此查询不包含UNION查询或者子查询
  • PRIMARY,表示此查询是最外层的查询
  • UNION,表示此查询是UNION的第二或随后的查询
  • DEPENDENT UNION, UNION中的第二或后面的查询语句,取决于外面的查询
  • UNION RESULT,UNION的结果
  • SUBQUERY, 子查询中的第一个SELECT
  • DEPENDENT SUBQUERY:子查询中第一个SELECT,取决于外面的查询,即子查询依赖于外层查询的结果。

table

表示查询设计的表或者衍生表(表别名)

  • 关联优化器会为查询选择关联顺序,左侧深度优先
  • 当from中有子查询的时候,表名是derivedN的形式,N指向子查询,也就是explain结果中的下一列
  • 当有Union result的时候,表名是Union 1,2等形式,1,2表示参与Union的query id
  • 注意:mysql对待这些表和普通表一样,但是临时表是没有任何索引的。

type

type字段比较重要,它提供了判断查询是否高效的重要依据,通过type字段我们判断此查询是全表扫描还是索引扫描等。

  • system:表中只有一条数据,这个类型是特殊的const类型
  • const:针对主键或唯一索引的等值查询扫描,最多只返回一行数据,const查询速度非常快,因为它仅仅读取一次即可。
  • eq_ref:此类型通常出现在多表的join查询,表示对于前表的每个结果,都只匹配到后表的一行结果,并且查询的比较操作通常是=,查询效率高。
  • ref:此类型通常出现在多表的join查询,针对于非唯一或非主键索引,或者使用了最左前缀规则索引的查询。
  • range:表示使用索引范围查询,通过索引字段范围获取表中部分数据记录,这个通常出现在: =, <>, >, >=, <, <=, IS NULL, <=>, BETWEEN, IN() 操作中。当type=range时,ref字段为null,并且key_len字段是此次查询中使用到的索引的最长的那个。
  • index:表示全索引扫描(full index scan), 和ALL类型类似,只不过ALL类型是全表扫描,而index类型则仅仅扫描所有的索引,而不扫描数据。index通常出现在:所要查询的数据直接在索引树种就可以获取到,而不需要扫描数据,当是这种情况时,extra字段会显示Using index
  • ALL:表示全表扫描,这个类型的查询是性能最差的查询之一,通常来说,我们的查询不应该出现ALL类型的查询,因为这样的查询在数据量大的情况下,对数据库的性能是巨大的灾难,一般可以用索引来避免

type类型的性能比较

ALL < index < range ≈ index_merge < ref < eq_ref < const < system

possible_keys

possible_keys表示mysql在查询时,能够使用到的索引,注意,即使有些索引在possible_keys中出现,但是不表示此索引会真正被Mysql使用到,Mysql在查询时具体使用了哪些索引,由key字段决定。

key

此字段是mysql在当前查询时所真正使用到的索引

key_len

表示查询优化器使用了索引的字节数,这个字段可以评估组合索引是否完全被使用,或只有最左部分字段被使用到。根据数据类型所占字节数计算出来。

  • 字符串

    • char(n): n 字节长度
    • varchar(n): 如果是 utf8 编码, 则是 3 n + 2字节; 如果是 utf8mb4 编码, 则是 4 n + 2 字节.
  • 数值类型:
    • TINYINT: 1字节
    • SMALLINT: 2字节
    • MEDIUMINT: 3字节
    • INT: 4字节
    • BIGINT: 8字节
  • 时间类型
    • DATE: 3字节
    • TIMESTAMP: 4字节
    • DATETIME: 8字节
  • 字段属性: NULL 属性 占用一个字节. 如果一个字段是 NOT NULL 的, 则没有此属性.

rows

rows也是一个重要的字段,mysql查询优化器根据统计信息,估算SQL要查找到结果集需要扫描读取的数据行数。这个值非常直观显示SQL的效率好坏,原则上rows越少越好。

Extra

explain中很多额外的信息都会在extra中显示,常见以下内容:

  • Using filesort,表示mysql需额外的排序操作,不能通过索引顺序达到排序效果,一般有Using filesort,都建议优化去掉,因为这样的查询CPU资源消耗大。
  • Using index,“覆盖索引扫描”,表示查询在索引树中就可以查询到所需数据,不用扫描表数据问题,往往说明性能挺好。
  • Using temporary,查询有使用临时表,一般出现于排序,分组和多表join的情况,查询效率不高,建议优化。

https://blog.tanteng.me/2017/01/mysql-explain/

最近慢慢接触MySQL,了解如何优化它也迫在眉睫了,话说工欲善其事,必先利其器。最近我就打算了解下几个优化MySQL中经常用到的工具。今天就简单介绍下EXPLAIN。

内容导航

  • id
  • select_type
  • table
  • type
  • possible_keys
  • key
  • key_len
  • ref
  • rows
  • Extra

环境准备

MySQL版本:

创建测试表

CREATE TABLE people(id bigint auto_increment primary key,zipcode char(32) not null default '',address varchar(128) not null default '',lastname char(64) not null default '',firstname char(64) not null default '',birthdate char(10) not null default ''
);CREATE TABLE people_car(people_id bigint,plate_number varchar(16) not null default '',engine_number varchar(16) not null default '',lasttime timestamp
);

插入测试数据

insert into people
(zipcode,address,lastname,firstname,birthdate)
values
('230031','anhui','zhan','jindong','1989-09-15'),
('100000','beijing','zhang','san','1987-03-11'),
('200000','shanghai','wang','wu','1988-08-25')insert into people_car
(people_id,plate_number,engine_number,lasttime)
values
(1,'A121311','12121313','2013-11-23 :21:12:21'),
(2,'B121311','1S121313','2011-11-23 :21:12:21'),
(3,'C121311','1211SAS1','2012-11-23 :21:12:21')

创建索引用来测试

alter table people add key(zipcode,firstname,lastname);

EXPLAIN 介绍

先从一个最简单的查询开始:

Query-1
explain select zipcode,firstname,lastname from people;

EXPLAIN输出结果共有id,select_type,table,type,possible_keys,key,key_len,ref,rows和Extra几列。

id

Query-2
explain select zipcode from (select * from people a) b;

id是用来顺序标识整个查询中SELELCT 语句的,通过上面这个简单的嵌套查询可以看到id越大的语句越先执行。该值可能为NULL,如果这一行用来说明的是其他行的联合结果,比如UNION语句:

Query-3
explain select * from people where zipcode = 100000 union select * from people where zipcode = 200000;

select_type

SELECT语句的类型,可以有下面几种。

SIMPLE

最简单的SELECT查询,没有使用UNION或子查询。见Query-1。

PRIMARY

在嵌套的查询中是最外层的SELECT语句,在UNION查询中是最前面的SELECT语句。见Query-2和Query-3。

UNION

UNION中第二个以及后面的SELECT语句。 见Query-3。

DERIVED

派生表SELECT语句中FROM子句中的SELECT语句。见Query-2。

UNION RESULT

一个UNION查询的结果。见Query-3。

DEPENDENT UNION

顾名思义,首先需要满足UNION的条件,及UNION中第二个以及后面的SELECT语句,同时该语句依赖外部的查询。

Query-4
explain select * from people where id in  (select id from people where zipcode = 100000 union select id from people where zipcode = 200000 );

Query-4中select id from people where zipcode = 200000的select_type为DEPENDENT UNION。你也许很奇怪这条语句并没有依赖外部的查询啊。

这里顺带说下MySQL优化器对IN操作符的优化,优化器会将IN中的uncorrelated subquery优化成一个correlated subquery(关于correlated subquery参见这里)。

SELECT ... FROM t1 WHERE t1.a IN (SELECT b FROM t2);

类似这样的语句会被重写成这样:

SELECT ... FROM t1 WHERE EXISTS (SELECT 1 FROM t2 WHERE t2.b = t1.a);

所以Query-4实际上被重写成这样:

Query-5
explain select * from people o where exists  (select id from people where zipcode = 100000 and id = o.id union select id from people where zipcode = 200000  and id = o.id);

题外话:有时候MySQL优化器这种太过“聪明” 的做法会导致WHERE条件包含IN()的子查询语句性能有很大损失。可以参看《高性能MySQL第三版》6.5.1关联子查询一节

SUBQUERY

子查询中第一个SELECT语句。

Query-6
explain select * from people  where id =  (select id from people where zipcode = 100000);

DEPENDENT SUBQUERY

和DEPENDENT UNION相对UNION一样。见Query-5。

除了上述几种常见的select_type之外还有一些其他的这里就不一一介绍了,不同MySQL版本也不尽相同。

table

显示的这一行信息是关于哪一张表的。有时候并不是真正的表名。

Query-7
explain select * from (select * from (select * from people a) b ) c;

可以看到如果指定了别名就显示的别名。

<derivedN>N就是id值,指该id值对应的那一步操作的结果。

还有<unionM,N>这种类型,出现在UNION语句中,见Query-4。

注意:MySQL对待这些表和普通表一样,但是这些“临时表”是没有任何索引的。

type

type列很重要,是用来说明表与表之间是如何进行关联操作的,有没有使用索引。MySQL中“关联”一词比一般意义上的要宽泛,MySQL认为任何一次查询都是一次“关联”,并不仅仅是一个查询需要两张表才叫关联,所以也可以理解MySQL是如何访问表的。主要有下面几种类别。

const

当确定最多只会有一行匹配的时候,MySQL优化器会在查询前读取它而且只读取一次,因此非常快。const只会用在将常量和主键或唯一索引进行比较时,而且是比较所有的索引字段。people表在id上有一个主键索引,在(zipcode,firstname,lastname)有一个二级索引。因此Query-8的type是const而Query-9并不是:

Query-8
explain select * from people where id=1;

Query-9
explain select * from people where zipcode = 100000;

注意下面的Query-10也不能使用const table,虽然也是主键,也只会返回一条结果。

Query-10
explain select * from people where id >2;

system

这是const连接类型的一种特例,表仅有一行满足条件。

Query-11
explain select * from (select * from people where id = 1 )b;

<derived2>已经是一个const table并且只有一条记录。

eq_ref

eq_ref类型是除了const外最好的连接类型,它用在一个索引的所有部分被联接使用并且索引是UNIQUE或PRIMARY KEY。

需要注意InnoDB和MyISAM引擎在这一点上有点差别。InnoDB当数据量比较小的情况type会是All。我们上面创建的people 和 people_car默认都是InnoDB表。

Query-12
explain select * from people a,people_car b where a.id = b.people_id;

我们创建两个MyISAM表people2和people_car2试试:

CREATE TABLE people2(id bigint auto_increment primary key,zipcode char(32) not null default '',address varchar(128) not null default '',lastname char(64) not null default '',firstname char(64) not null default '',birthdate char(10) not null default ''
)ENGINE = MyISAM;CREATE TABLE people_car2(people_id bigint,plate_number varchar(16) not null default '',engine_number varchar(16) not null default '',lasttime timestamp
)ENGINE = MyISAM;

Query-13
explain select * from people2 a,people_car2 b where a.id = b.people_id;

我想这是InnoDB对性能权衡的一个结果。

eq_ref可以用于使用 = 操作符比较的带索引的列。比较值可以为常量或一个使用在该表前面所读取的表的列的表达式。如果关联所用的索引刚好又是主键,那么就会变成更优的const了:

Query-14
explain select * from people2 a,people_car2 b where a.id = b.people_id and b.people_id = 1;

ref

这个类型跟eq_ref不同的是,它用在关联操作只使用了索引的最左前缀,或者索引不是UNIQUE和PRIMARY KEY。ref可以用于使用=或<=>操作符的带索引的列。

为了说明我们重新建立上面的people2和people_car2表,仍然使用MyISAM但是不给id指定primary key。然后我们分别给id和people_id建立非唯一索引。

reate index people_id on people2(id);
create index people_id on people_car2(people_id);

然后再执行下面的查询:

Query-15
explain select * from people2 a,people_car2 b where a.id = b.people_id and a.id > 2;

Query-16
explain select * from people2 a,people_car2 b where a.id = b.people_id and a.id = 2;

Query-17
explain select * from people2 a,people_car2 b where a.id = b.people_id;

Query-18
explain select * from people2 where id = 1;

看上面的Query-15,Query-16和Query-17,Query-18我们发现MyISAM在ref类型上的处理也是有不同策略的。

对于ref类型,在InnoDB上面执行上面三条语句结果完全一致。

fulltext

链接是使用全文索引进行的。一般我们用到的索引都是B树,这里就不举例说明了。

ref_or_null

该类型和ref类似。但是MySQL会做一个额外的搜索包含NULL列的操作。在解决子查询中经常使用该联接类型的优化。(详见这里)。

Query-19
mysql> explain select * from people2 where id = 2 or id is null;

Query-20
explain select * from people2 where id = 2 or id is not null;

注意Query-20使用的并不是ref_or_null,而且InnnoDB这次表现又不相同(数据量大的情况下有待验证)。

index_merger

该联接类型表示使用了索引合并优化方法。在这种情况下,key列包含了使用的索引的清单,key_len包含了使用的索引的最长的关键元素。关于索引合并优化看这里。

unique_subquery

该类型替换了下面形式的IN子查询的ref:

value IN (SELECT primary_key FROM single_table WHERE some_expr)

unique_subquery是一个索引查找函数,可以完全替换子查询,效率更高。

index_subquery

该联接类型类似于unique_subquery。可以替换IN子查询,但只适合下列形式的子查询中的非唯一索引:

value IN (SELECT key_column FROM single_table WHERE some_expr)

range

只检索给定范围的行,使用一个索引来选择行。key列显示使用了哪个索引。key_len包含所使用索引的最长关键元素。在该类型中ref列为NULL。当使用=、<>、>、>=、<、<=、IS NULL、<=>、BETWEEN或者IN操作符,用常量比较关键字列时,可以使用range:

Query-21
explain select * from people where id = 1 or id = 2;


注意在我的测试中:发现只有id是主键或唯一索引时type才会为range。

这里顺便挑剔下MySQL使用相同的range来表示范围查询和列表查询。

explain select * from people where id >1;

 explain select * from people where id in (1,2);

但事实上这两种情况下MySQL如何使用索引是有很大差别的:

我们不是挑剔:这两种访问效率是不同的。对于范围条件查询,MySQL无法使用范围列后面的其他索引列了,但是对于“多个等值条件查询”则没有这个限制了。

——出自《高性能MySQL第三版》

index

该联接类型与ALL相同,除了只有索引树被扫描。这通常比ALL快,因为索引文件通常比数据文件小。这个类型通常的作用是告诉我们查询是否使用索引进行排序操作。

Query-22
explain select * from people order by id;

至于什么情况下MySQL会利用索引进行排序,等有时间再仔细研究。最典型的就是order by后面跟的是主键。

ALL

最慢的一种方式,即全表扫描。

总的来说:上面几种连接类型的性能是依次递减的(system>const),不同的MySQL版本、不同的存储引擎甚至不同的数据量表现都可能不一样。

possible_keys

possible_keys列指出MySQL能使用哪个索引在该表中找到行。

key

key列显示MySQL实际决定使用的键(索引)。如果没有选择索引,键是NULL。要想强制MySQL使用或忽视possible_keys列中的索引,在查询中使用FORCE INDEX、USE INDEX或者IGNORE INDEX。

key_len

key_len列显示MySQL决定使用的键长度。如果键是NULL,则长度为NULL。使用的索引的长度。在不损失精确性的情况下,长度越短越好 。

ref

ref列显示使用哪个列或常数与key一起从表中选择行。

rows

rows列显示MySQL认为它执行查询时必须检查的行数。注意这是一个预估值。

Extra

Extra是EXPLAIN输出中另外一个很重要的列,该列显示MySQL在查询过程中的一些详细信息,包含的信息很多,只选择几个重点的介绍下。

Using filesort

MySQL有两种方式可以生成有序的结果,通过排序操作或者使用索引,当Extra中出现了Using filesort 说明MySQL使用了后者,但注意虽然叫filesort但并不是说明就是用了文件来进行排序,只要可能排序都是在内存里完成的。大部分情况下利用索引排序更快,所以一般这时也要考虑优化查询了。

Using temporary

说明使用了临时表,一般看到它说明查询需要优化了,就算避免不了临时表的使用也要尽量避免硬盘临时表的使用。

Not exists

MYSQL优化了LEFT JOIN,一旦它找到了匹配LEFT JOIN标准的行, 就不再搜索了。

Using index

说明查询是覆盖了索引的,这是好事情。MySQL直接从索引中过滤不需要的记录并返回命中的结果。这是MySQL服务层完成的,但无需再回表查询记录。

Using index condition

这是MySQL 5.6出来的新特性,叫做“索引条件推送”。简单说一点就是MySQL原来在索引上是不能执行如like这样的操作的,但是现在可以了,这样减少了不必要的IO操作,但是只能用在二级索引上,详情点这里。

Using where

使用了WHERE从句来限制哪些行将与下一张表匹配或者是返回给用户。

注意:Extra列出现Using where表示MySQL服务器将存储引擎返回服务层以后再应用WHERE条件过滤。

EXPLAIN的输出内容基本介绍完了,它还有一个扩展的命令叫做EXPLAIN EXTENDED,主要是结合SHOW WARNINGS命令可以看到一些更多的信息。一个比较有用的是可以看到MySQL优化器重构后的SQL。

Ok,EXPLAIN了解就到这里,其实这些内容网上都有,只是自己实际操练下会印象更深刻。下一节会介绍SHOW PROFILE、慢查询日志以及一些第三方工具。

http://www.cnblogs.com/zhanjindong/p/3439042.html

转载于:https://www.cnblogs.com/softidea/p/5683068.html

MySQL优化—工欲善其事,必先利其器之EXPLAIN相关推荐

  1. 18.mysql优化(三)–explain分析sql语句执行效率

    原文地址:http://www.cnblogs.com/hailexuexi/archive/2011/11/20/2256020.html Explain命令在解决数据库性能上是第一推荐使用命令,大 ...

  2. 【MySQL优化】——看懂explain

    explain explain模拟优化器执行SQL语句,在5.6以及以后的版本中,除过select,其他比如insert,update和delete均可以使用explain查看执行计划,从而知道mys ...

  3. MySQL优化—工欲善其事,必先利其器(2)

    http://www.cnblogs.com/magialmoon/p/3472804.html点击打开链接 上一篇文章简单介绍了下EXPLAIN的用法,今天主要介绍以下几点内容: 慢查询日志 打开慢 ...

  4. mysql 优化关键字_Mysql之Explain关键字及常见的优化手段

    Explain关键字字段描述: Explain关键字字段详情描述 id 我们写的查询语句一般都以SELECT关键字开头,比较简单的查询语句里只有一个SELECT关键字,但是下边两种情况下在一条查询语句 ...

  5. mysql如何explan优化sql_《MySQL数据库》MySQL 优化SQL(explain)

    前言 如果要写出优质的SQL语句,就需要了解MySQL的存储原理.MySQL是如何分析SQL,如何利用索引查询. Explain 关键字 explain select * from ic_base;  ...

  6. 用MySql的查询分析语法explain来优化查询和索引

    http://hi.baidu.com/wtnzone/item/beb83840a4971af4dd0f6c77 数据库最常见的操作就是查询了,我们经常要用"SELECT"语法对 ...

  7. MySQL优化从执行计划开始(explain超详细)

    前言 小伙伴一定遇到过这样反馈:这页面加载数据太慢啦,甚至有的超时了,用户体验极差,需要赶紧优化: 反馈等同于投诉啊,多有几次,估计领导要找你谈话啦. 于是不得不停下手里头的活,赶紧进行排查,最终可能 ...

  8. mysql 数据库优化之执行计划(explain)简析

    数据库优化是一个比较宽泛的概念,涵盖范围较广.大的层面涉及分布式主从.分库.分表等:小的层面包括连接池使用.复杂查询与简单查询的选择及是否在应用中做数据整合等:具体到sql语句执行效率则需调整相应查询 ...

  9. MySQL 优化 —— EXPLAIN 执行计划详解

    引言 本博客大部分内容翻译自MySQL 官网 Understanding the Query Execution Plan 专题.另外有一些补充,则来自于网课以及<高性能MySQL(第三版)&g ...

最新文章

  1. linuxmysql乱码
  2. 合肥天鹅湖万达广场机器人_万达王健林再考察合肥!瞄准政务、高新,年末合肥楼市出现区域分化!...
  3. 花开的声音 - 张靓颖
  4. openjudge 14:求10000以内n的阶乘
  5. Xdebug部分配置选项说明
  6. 免费干货课程!发放官方证书!参与更有礼品相送!戳进绝不后悔~
  7. VSCode如何进入到终端中
  8. 品优影视建站系统1.3.6.5开源绿色版
  9. 微信抢红包插件与Android辅助功能
  10. linux环境 下载Neo4j
  11. 随机数C语言 (就做个笔记储存一下)
  12. Bootstrap学习(九)collapse折叠窗口、carousel轮播效果、Affix侧边栏
  13. 方差分析介绍(结合COVID-19案例)
  14. mysql历史表_MySQL历史表设计和查询
  15. matlab摩托车刹车问题,摩托车刹车你用对了吗?老司机都不一定会用后刹
  16. Power Supply---驱动框架
  17. 蔚来大逆转:去年最惨,现在最富
  18. Linux(二十七):在Linux系统上安装Git
  19. Linux 如何设置密码复杂度?
  20. 画论01 顾恺之《画云台山记》

热门文章

  1. thinkphp执行流程
  2. ExtJs4 笔记(8) Ext.slider 滚轴控件、 Ext.ProgressBar 进度条控件、 Ext.Editor 编辑控件...
  3. Microsoft System Center 2012:将系统管理带入云中
  4. I need to follow my heart.
  5. C#汉字转拼音(npinyin)将中文转换成拼音全文或首字母
  6. ArcGIS Engine中的Symbols详解
  7. 设置更改root密码(远程,本地)、连接mysql、mysql常用命令
  8. ContextCompat.checkSelfPermission()方法中的第二个参数
  9. 链接被点击的默认行为——带到另一个窗口
  10. Unity Shader 阴影