提示:explain详解、explain中index和ref的区别?
mysql中的explain的每个字段的解释。本人水平有限,如有误导,欢迎斧正,一起学习,共同进步!
这里直接放两张图吧,拿innodb来说,他的普通索引和主键索引的区别。其实关于索引,网上的定义很多,一级索引、二级索引、聚合索引、聚集索引、普通索引…大家可能有点晕。简单的说:一级索引=主键索引=聚集索引。二级索引=普通索引=非聚集索引。其实博主的另一篇博客写的更加详细,大家感兴趣的话,可以去看看另一篇。
主键索引的叶子节点,存储的是当前数据行的全部字段的内容。innoDB,只有一个主键(聚簇)索引,如果你有主键,则主键去组织这个B+Tree的结构,如果你没自增主键,则mysql会自己维护一个隐藏列去当主键去维护B+Tree的结构。
非主键索引的叶子节点,存储的是当前数据行的,主键索引的磁盘地址。这就是,为什么非主键索引需要回表的原因,因为他不包含全部的字段内容。当然,如果查询方式为覆盖索引的话,也不需要回表了。
总的来说,explain中,比较重要的几个参数是:type、rows、key、possible_key、extra。绝大多数情况下,你甚至可以只看type、rows。rows是mysql本次查询可能要查询的行数,这个值越小越好。type的查询效率从最优到最差分别为:system > const > eq_ref > ref > range > index > ALL
id列的编号是select的序号,有几个select就有几个id,并且id的顺序是按select出现的顺序增长的。
id不一定是唯一的,id列越大执行优先级越高,id相同则从上往下执行,id为null最后执行。
取值范围如下:
table就是查的哪张表,没啥可说的。
partitions是分区的意思。一般有分区的时候,有这个。相对比较少见。
type列比较关键。上面咱们也说了,他的效率从最优到最差分别为:system > const > eq_ref > ref > range > index > ALL。
NULL:mysql能在优化阶段分解查询语句,在执行阶段不在访问表或者语句。例如:在索引列中选取最小值,可以单独去查索引完成,不需要再执行时访问表。
const:mysql能对查询的结果进行优化,并将其转化为一个常量(可以看做是show warning的结果)。一般是用primary key 或者unique key的所有列与常数比较时,所以表最多有一个匹配行,读取一次,速度比较快。(一般是主键或者唯一索引的时候,会是const)
system:system是const的特例。表里只有一条元素匹配时,为system。(我理解的是,表里有多条记录,通过唯一值查时是const;整个表里就一条记录,通过唯一值查时,是system)要查询的结果集,本身就只有一行记录,为system。
eq_ref:primary key 或者unique key索引的所有部分被连接使用,最多只会返回一条符合条件的记录。这可能是在const以外最好的连接类型了。简单的select查询不会出现这种type。(简单的说,关联查询条件是主键或者唯一索引,就是这种类型)
ref:不是使用的唯一索引,而是使用的普通索引或者唯一索引的部分前缀。索引要和某个值比较,可能会找到多个记录。(走索引了,但是走的普通索引,不是主键索引,就是ref)
range: 范围扫描。通常出现在 in()、between、>、<、>=等操作。使用一个索引来给定范围的行。普通索引、主键索引都行。(也走索引了,但是是范围,肯定没前面的几种快)
index:扫描全索引就能拿到结果。一般是扫描某个二级索引,这种扫描不会从索引树根节点开始快速查找。而是直接对二级索引的叶子节点遍历和扫描,速度还是比较慢的,这种查询一般为使用覆盖索引,二级索引一般比较小,所以这种通常比all快一些。
知识点:为什么select * from ,但是会走索引呢?key = idx_name 。因为二级索引会存索引,还会存这个索引对应的一级索引。而这个user表一共就id、name俩字段。name是二级索引,name下的叶子节点存的是主键索引(也就是id),也就是说,只扫描二级索引就能查到全部的数据了,那肯定就走的二级索引。前面“知识点”这段话,就是覆盖索引的原理。
all:全表扫描。他是根据主键索引,去挨着扫描,全部的叶子节点。听起来跟index比较像,只不过index是扫描全部的普通索引的叶子节点,而all是扫描全部的主键索引的叶子节点。(因为主键索引的叶子节点有全部的行数据。)
possible_keys:这个执行过程中,可能会用到的索引。(显示的是,这个查询,可能会用到的哪些索引。比如说,mysql分析的时候,觉得你走a索引会快。容纳后possible_key就是a,但是真正执行的时候,mysql发现不用这个索引,全表可能更快,然后key就是空了。就是分析的possible_keys有索引,实际key没走索引)。mysql认为可能会走的索引(实际可能没走)。
key: 这条语句,执行过程中,真正用到的索引。(显示的是mysql实际采用哪个索引来优化对该表的访问)。mysql在本次查询中,真正有没有走索引。possible_keys是可能会用到的索引,key是真正有没有走索引。
如果你的explain是这种情况:
key_len:显示的是,mysql在索引里,使用的字节数。可以判断出来,具体使用了索引中的哪些列。比如你的联合索引,俩个int类型,第一个字段是int占了4字节,第二个字段也是int,也占了4字节,如果key_len是4的话,说明使用了联合索引的前一个字段,如果key_len是8的话,说明使用了联合索引的俩字段。
之所以是5,是因为int占了4个字节;字段允许为null,需要1个字节去记录是否为空,所以是5字节。
key_len的计算规则:
ref:在key列记录的索引中,表查找值所用到的列或常量,常见的有:const、 字段名(如 film.id)
row:这个行数是mysql预估要读取并检测的行数,注意这个不是结果集里的行数。是估计要扫描多少行,才能拿到结果。越小越好,越小查的越快
extra:这一列是展示的额外信息。一共可能有几十种,下面列举了一些比较常用的。(大概了解一下就行)
Using index:使用覆盖索引。意思就是说,在这次查询中,我只查索引(一般是指普通索引),就能查到全部的结果集(因为普通索引的叶子节点是主键索引),并不需要再根据主键索引去回表,查其他数据。
有 Using index 代表不会回表。比extra为空时(会回表)的效率高。
Using where:使用 where 语句来处理结果,并且查询的列未被索引覆盖。就是说,salary不是索引,就是普通的查询。
Using index condition:查询的列不完全被索引覆盖,where条件中是一个前导列的范围;
Using temporary: 是走了临时表的,比如说你是distinct name。name不是索引的话,mysql就会先把数据搂出来,搂出来以后,去放一个临时表,然后在临时表中,一行一行的,逐行去重,去完重以后,再从临时表中拿数据,去展示。
因为他是索引,而索引是有序的,mysql在扫描索引的时候,一看这俩一样,就直接去重了,所以不在需要临时表去去重了,所以更快一些。
将用外部排序而不是索引排序,数据较小时从内存排序,否则需要在磁盘完成排序。这种情况下一般也是要考虑使用索引来优化的。
使用某些聚合函数(比如 max、min)来访问存在索引的某个字段、
explain可以极大的方便我们排查问题,因此,熟悉掌握explain对于后端开发来说是很有必要的。