高性能MySql第三版 阅读简记(3)

目录

调用EXPLAIN

一些说明:       

EXPLAIN中的列

id列

select_type列

table列

 type列

possibIe_keys列

key列

key_len列

ref列

rows列

fiItered列

Extra列


调用EXPLAIN

要使用EXPLAIN,只需在查询中的SELECT关键字之前增加EXPLAIN这个词。

例如:

explain select * from demo;

一些说明:       

认为增加EXPLAIN时MySQL不会执行查询,这是一个常见的错误。事实上,如果查询在FROM子句中包括子查询,那么MySQL实际上会执行子查询,将其结果放在一个临时表中,然后完成外层查询优化。它必须在可以完成外层查询优化之前处理所有类似的子查询,这对于EXPLAIN来说是必须要做的(1)。这意味着如果语句包含开销较大的子查询或使用临时表算法的视图,实际上会给服务器带来大量工作。

       要意识到EXPLAIN只是个近似结果,别无其他。有时候它是一个很好的近似,但在其他时候,可能与真相相差甚远。以下是一些相关的限制。

  •  EXPLAIN根本不会告诉你触发器、存储过程或UDF会如何影响查询。
  • 它并不支持存储过程,尽管可以手动抽取查询并单独地对其进行EXPLAIN操作。
  • 它并不会告诉你MySQL在查询执行中所做的特定优化。
  • 它并不会显示关于查询的执行计划的所有信息(MySQL开发者会尽可能增加更多信息)。
  • 它并不区分具有相同名字的事物。例如,它对内存排序和临时文件都使用“filesort”,并且对于磁盘上和内存中的临时表都显示“Usingtemporary”。
  • 可能会误导。例如,它会对一个有着很小LIMIT的查询显示全索引扫描。

EXPLAIN中的列

EXPLAIN的输出总是有相同的列(只有EXPLAIN EXTENDED在MySQL 5.1中增加了一个filtered列,EXPLAIN PARTITIONS增加了一个Partitions列)。可变的是行数及内容。然而,为了保持我们的例子简洁明了,我们在本附录中不总是显示所有的列。

在接下来的小节中,我们将展示在EXPLAIN结果中每一列的意义。记住,输出中的行以MySQL实际执行的查询部分的顺序出现,而这个顺序不总是与其在原始SQL中的相一致。

id列

这一列总是包含一个编号,标识SELECT所属的行。如果在语句当中没有子查询或联合,那么只会有唯一的SELECT,于是每一行在这个列中都将显示一个1。否则,内层的SELECT语句一般会顺序编号,对应于其在原始语句中的位置。

MySQL将SELECT查询分为简单和复杂类型,复杂类型可分成三大类:简单子查询、所谓的派生表(在FROM子句中的子查询)(3),以及UNION查询。下面是一个简单的子查询。

FROM子句中的子查询和联合给id列增加了更多复杂性。下面是一个FROM子句中的基本子查询。

如你所知,这个查询执行时有一个匿名临时表。MySQL内部通过别名(der)在外层查询中引用这个临时表,在更复杂的查询中可以看到ref列。

注意UNION结果输出中的额外行。UNION结果总是放在一个匿名临时表中,之后MySQL将结果读取到临时表外。临时表并不在原SQL中出现,因此它的id列是NULL。与之前的例子相比(演示子查询的那个FROM子句中),从这个查询产生的临时表在结果中出现在最后一行,而不是第一行。

到目前为止这些都非常直截了当,但这三类语句的混合则会使输出变得非常复杂,我们稍后就会看到。

select_type列

这一列显示了对应行是简单还是复杂SELECT(如果是后者,那么是三种复杂类型中的哪一种)。SIMPLE值意味着查询不包括子查询和UNION。如果查询有任何复杂的子部分,则最外层部分标记为PRIMARY,其他部分标记如下。

SUBQUERY

包含在SELECT列表中的子查询中的SELECT(换句话说,不在FROM子句中)标记为SUBQUERY。

DERIVED

DERIVED值用来表示包含在FROM子句的子查询中的SELECT,MySQL会递归执行并将结果放到一个临时表中。服务器内部称其“派生表”,因为该临时表是从子查询中派生来的。

UNION

在UNION中的第二个和随后的SELECT被标记为UNION。第一个SELECT被标记就好像它以部分外查询来执行。这就是之前的例子中在UNION中的第一个SELECT显示为PRIMARY的原因。如果UNION被FROM子句中的子查询包含,那么它的第一个SELECT会被标记为DERIVED。

UNION RESULT

用来从UNION的匿名临时表检索结果的SELECT被标记为UNION RESULT。除了这些值,SUBQUERY和UNION还可以被标记为DEPENDENT和UNCACHEABLE。DEPENDENT意味着SELECT依赖于外层查询中发现的数据;UNCACHEABLE意味着SELECT中的某些特性阻止结果被缓存于一个Item_cache中。(Item_cache未被文档记载;它与查询缓存不是一回事,尽管它可以被一些相同类型的构件否定,例如RAND()函数。)

table列

这一列显示了对应行正在访问哪个表。在通常情况下,它相当明了:它就是那个表,或是该表的别名(如果SQL中定义了别名)。

 type列

ALL

人们所称的全表扫描,通常意味着MySQL必须扫描整张表,从头到尾,去找到需要的行。(这里也有个例外,例如在查询里使用了LIMIT,或者在Extra列中显示“Using distinct/not exists”。)

index

这个跟全表扫描一样,只是MySQL扫描表时按索引次序进行而不是行。它的主要优点是避免了排序;最大的缺点是要承担按索引次序读取整个表的开销。这通常意味着若是按随机次序访问行,开销将会非常大。如果在Extra列中看到“Using index”,说明MySQL正在使用覆盖索引,它只扫描索引的数据,而不是按索引次序的每一行。它比按索引次序全表扫描的开销要少很多。

range

范围扫描就是一个有限制的索引扫描,它开始于索引里的某一点,返回匹配这个值域的行。这比全索引扫描好一些,因为它用不着遍历全部索引。显而易见的范围扫描是带有BETWEEN或在WHERE子句里带有>的查询。当MySQL使用索引去查找一系列值时,例如IN()和OR列表,也会显示为范围扫描。然而,这两者其实是相当不同的访问类型,在性能上有重要的差异。更多信息可以查看第5章的文章“什么是范围条件”。此类扫描的开销跟索引类型相当。

ref

这是一种索引访问(有时也叫做索引查找),它返回所有匹配某个单个值的行。然而,它可能会找到多个符合条件的行,因此,它是查找和扫描的混合体。此类索引访问只有当使用非唯一性索引或者唯一性索引的非唯一性前缀时才会发生。把它叫做ref是因为索引要跟某个参考值相比较。这个参考值或者是一个常数,或者是来自多表查询前一个表里的结果值。ref_or_null是ref之上的一个变体,它意味着MySQL必须在初次查找的结果里进行第二次查找以找出NULL条目。

eq_ref

使用这种索引查找,MySQL知道最多只返回一条符合条件的记录。这种访问方法可以在MySQL使用主键或者唯一性索引查找时看到,它会将它们与某个参考值做比较。MySQL对于这类访问类型的优化做得非常好,因为它知道无须估计匹配行的范围或在找到匹配行后再继续查找。

const, system

当MySQL能对查询的某部分进行优化并将其转换成一个常量时,它就会使用这些访问类型。举例来说,如果你通过将某一行的主键放入WHERE子句里的方式来选取此行的主键,MySQL 就能把这个查询转换为一个常量。然后就可以高效地将表从联接执行中移除。

NULL

这种访问方式意味着MySQL能在优化阶段分解查询语句,在执行阶段甚至用不着再访问表或者索引。例如,从一个索引列里选取最小值可以通过单独查找索引来完成,不需要在执行时访问表。

possibIe_keys列

这一列显示了查询可以使用哪些索引,这是基于查询访问的列和使用的比较操作符来判断的。这个列表是在优化过程的早期创建的,因此有些罗列出来的索引可能对于后续优化过程是没用的。

key列

这一列显示了MySQL 决定采用哪个索引来优化对该表的访问。如果该索引没有出现在possible_keys列中,那么MySQL选用它是出于另外的原因——例如,它可能选择了一个覆盖索引,哪怕没有WHERE子句。

换句话说,possible_keys揭示了哪一个索引能有助于高效地行查找,而key显示的是优化采用哪一个索引可以最小化查询成本

key_len列

该列显示了MySQL在索引里使用的字节数。如果MySQL正在使用的只是索引里的某些列,那么就可以用这个值来算出具体是哪些列。要记住,MySQL 5.5及之前版本只能使用索引的最左前缀。举例来说,sakila.film_actor的主键是两个SMALLINT列,并且每个SMALLINT列是两字节,那么索引中的每项是4字节。

ref列

这一列显示了之前的表在key列记录的索引中查找值所用的列或常量。

rows列

这一列是MySQL估计为了找到所需的行而要读取的行数。这个数字是内嵌循环关联计划里的循环数目。也就是说它不是MySQL认为它最终要从表里读取出来的行数,而是MySQL为了找到符合查询的每一点上标准的那些行而必须读取的行的平均数。

fiItered列

这一列是在MySQL 5.1里新加进去的,在使用EXPLAIN EXTENDED时出现。它显示的是针对表里符合某个条件(WHERE子句或联接条件)的记录数的百分比所做的一个悲观估算。如果你把rows列和这个百分比相乘,就能看到MySQL估算它将和查询计划里前一个表关联的行数。在写作本书的时候,优化器只有在使用ALL、index、range和index_merge访问方法时才会用这一估算。

Extra列

这一列包含的是不适合在其他列显示的额外信息。MySQL用户手册里记录了大多
数可以在这里出现的值。其中许多在本书中已经提到过。

常见的最重要的值如下。

“Using index”

此值表示MySQL将使用覆盖索引,以避免访问表。不要把覆盖索引和index访问类型弄混了。

“Using where”

这意味着MySQL服务器将在存储引擎检索行后再进行过滤。许多WHERE条件里涉及索引中的列,当(并且如果)它读取索引时,就能被存储引擎检验,因此不是所有带WHERE子句的查询都会显示“Using where”。有时“Usingwhere”的出现就是一个暗示:查询可受益于不同的索引。

“Using temporary”

这意味着MySQL在对查询结果排序时会使用一个临时表。

“Using filesort”

这意味着MySQL会对结果使用一个外部索引排序,而不是按索引次序从表里读取行。MySQL有两种文件排序算法,你可以在第6章读到相关内容。两种方式都可以在内存或磁盘上完成。EXPLAIN不会告诉你MySQL将使用哪一种文件排序,也不会告诉你排序会在内存里还是磁盘上完成。

“Range checked for each record (index map: N)”

这个值意味着没有好用的索引,新的索引将在联接的每一行上重新估算。N是显示在possible_keys列中素引的位图,并且是冗余的。

说明:当前内容为从书中摘抄部分文字,添加部分例子,已记录自己所得.如有侵权,请联系删除!

请大家多多关注此微信公众号。谢谢!

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值