Explain

通过Explain + 一条SQL语句,可以得到SQL执行的大体情况。

Type列

表示MySQL如何查找表中的行,即大概的查找范围。
最优 > 最差 : system > const > eq_ref > ref > range > index > ALL
例如:

  1. explain select * from authors;

会得到type为ALL,即查找了所有文档,效率必然不行。

通常情况下,我们需要保证查询达到range级别,最好达到ref。

此外,type还可能为NULL,例如:

  1. explain select min(id) from authors;

Const 和 System

const 表示常量级别,例如对主键进行查询:

  1. explain select * from articles a where a.id = 1;

image.png

但是如果要查的字段没有设置索引,则是all,

  1. explain select * from articles a where a.title = "哈哈哈";

image.png

System则效率更高,当是从一条记录里进行查询时,为System

eq_ref

主键的所有部分被连接使用,例如做联表查询时,某个表的主键作为了联表查询的条件:

  1. explain select * from articles a left join authors a2 on a.author_id = a2.id ;

因为a2.id中,id为主键,所以此处查询为eq_ref级别,效率也很高,次于const。
image.png

ref

会用到索引,但不是唯一索引,而是使用普通索引。

range

用了索引,但是是范围搜索,例如:

explain select * from articles a where a.id > 1;

index

扫描全索引拿到结果,一般是扫描某个二级索引,不会从根节点遍历,而是直接从二级索引的叶子节点遍历,速度还是比较慢的,只比all快。

ref和index的区别:
ref是真正用到了索引,从根节点开始查找, 效率比index要高;
index是遍历了二级索引的叶子节点;
例如:

// 下边用到了ref,从根节点开始查找
select * from articles where title = '哈哈哈';

// 下边直接遍历了索引的叶子节点
select * from articles;

ALL

全局扫描,需要优化。通常加入索引进行优化。All扫描了所有的聚簇索引,效率非常低,比遍历二级索引还低,因为聚簇索引体积更大,需要更多次的IO,IO很耗时。

为什么会有NULL呢?
因为我们数据是以B+树存储的,B+树是有序的,而且id是主键,那么只需要去拿B+树的第一个值即可,都不需要访问索引和数据表。

Key_len列

表示MySQL在索引里使用的字节数,通过该值,可以算出使用的是哪些索引。例如:
image.png
表中有联合索引idx_film_actor_id,由两个字段组成,每个字段是4字节。因为key_len = 4,可知道用了第一个列,即film_id作为索引。

注意:
Char: 3n字节
Varchar:3n + 2字节

Extra列

Using index: 使用覆盖索引

指的是,查询的字段都在次级索引的结果集中,此时不需要回表,即为Using index。
例如:

select film_id from film_actor where film_id = 1;

其中id为主键,那么只需要通过查找film_id的索引树,即可获得查询的所有字段(此处为film_id),而不需要先通过查询film_id索引树拿到主键id, 然后通过主索引id来查找其他字段。

Using where

指的是通过where语句来处理结果,而且查询的列未被索引覆盖。

select * from actor where name = 'a';

当name没有设置索引时,extra列中会显示Using where,这种情况通常都是需要优化的。

Using index condition

指的是要查询的字段没有完全被索引覆盖

Using file sort

指的是,当我们需要排序,而且排序字段不是索引时,extra中显示Using file sort。

例如:

select * from actor order by name;

以上查询,如果name不是索引,那么就会显示Using file sort。 需要被优化,因为如果查询的数据量很大,可能无法放进内存中排序,可能会用到磁盘排序,相当慢。

如果:

select * from file order by name;

如果在film表中,name是一个索引,那么当order by name时可以直接去拿name的叶子节点,因为已经排好序了,然后再通过主索引查到所有的数据即可。此时显示的不是Using file sort而是Using index。

当为空时,表示回表了,例如:

select film_id, remark from film_actor where film_id = 1;