一、什么是explain

使用EXPLAIN关键字可以模拟优化器执行SQL查询语句,从而知道MySQL是如何处理你的SQL语句。分析你的查询语句或是表结构的性能瓶颈。

二、explain用法

2.1 id列

2.11 id相同,执行顺序由上往下
圖片.png
2.12 如果是子查询,id的序号会递增,id值越大优先级越高,越先被执行
圖片.png
2.13 id相同不同,同时存在
圖片.png
解释:id值如果相同,可以认为是一组,从上往下顺序执行;在所有组中,id值越大,优先级越高,越先执行``。

2.2 select_type列

select_type表示对应行是简单还是复杂的查询

  • simple:简单查询,查询不包含子查询和union
  • primary:复杂查询中的最外层的select
  • subqueery:包含在select中的子查询(不在from子句中)
  • devived:临时表查询,包含在from子句中的子查询,mysql会将结果存放在一个临时表中(也称派生表)
  • union:在union中的第二个和随后的select

    圖片.png

2.3 table列

这一列表示explain正在访问哪个表,当from子句中有子查询时,table列是格式,表示当前查询依赖id=N的查询,于是先执行id=N的查询
当有union时,union result的table列的值为,表示1和2参与union的select行id

2.4 type列(重点)

这一列表示关联类型或访问类型,即MySQL决定如何查找表中的行,查找数据行记录的大概范围。依次从最优到最差分别为:system > const > eq_ref > ref > range > index > ALL**一般来说需要保证查询达到_r__ange级别,最好达到ref。_
2.4.1 ALL:全表扫描。扫描你的聚簇索引的所有叶子节点。通常情况下这需要增加索引来进行优化了
圖片.png
2.4.2 index:扫描全索引就能拿到结果,一般是扫描某个二级索引,这种扫描不会从索引树根节点开始快速查找,而是直接 对二级索引的叶子节点遍历和扫描,速度还是比较慢的,这种查询一般为使用覆盖索引,二级索引一般比较小,所以这 种通常比ALL快一些。(name为索引,id和name都在二级索引树中)
圖片.png
2.4.3 range:只索引给定范围的行,使用一个索引来选择行。key列显示使用了哪个索引,一般就是在你的where语句中出现了between、< 、>、in等查询,这种范围扫描索引扫描比权标扫描要好,因为它只需要开始与索引的某一点,而结束于另一点,不用扫描全部索引。
圖片.png
2.4.4 ref :相比 eq_ref,不使用唯一索引,而是使用普通索引或者唯一性索引的部分前缀,索引要和某个值相比较,可能会 找到多个符合条件的行。
1)、简单的select查询,非唯一索引(name为非唯一索引)
圖片.png
2)、关联表查询,col_role_id是col_role_id和col_id的联合索引,这里使用到了cx_admin_role的左边前缀 col_id部分。
圖片.png
2.4.5 eq_ref :primary key 或 unique key 索引的所有部分被连接使用 ,最多只会返回一条符合条件的记录。这可能是在 const 之外最好的联接类型了,简单的 select 查询不会出现这种 type,主键索引和唯一索引的关联查询为eq_ref;
圖片.png
2.4.6 system、const:mysql能对查询的某部分进行优化并将其转化成一个常量(可以看show warnings 的结果)。用于 primary key 或 unique key 的所有列与常数比较时,所以表最多有一个匹配行,读取1次,速度比较快;system是 const的特例,表里只有一条元组匹配时为system,表里只有一条数据。
圖片.png
2.4.7 null**:mysql能够在优化阶段分解查询语句,在执行阶段用不着再访问表或索引。例如:在索引列中选取最小值,可 以单独查找索引来完成,不需要在执行时访问表
圖片.png

2.5 possible_keys列

possible_keys显示可能应用在这张表中的索引,一个或多个。查询涉及到的字段上若存在索引,则该索引将被列出,但不一定被查询实际使用。possible_keys显示为空,表示没有用到索引。
圖片.png

2.6 key列

这一列显示mysql实际采用哪个索引来优化对该表的访问。 如果没有使用索引,则该列是 NULL。如果想强制mysql使用或忽视possible_keys列中的索引,在查询中使用 force index、ignore index。


2.7 key_len列

这一列显示了mysql在索引里使用的字节数,通过这个值可以算出具体使用了索引中的哪些列。 举例来说,cx_admin的联合索引 col_role_id 由 col_admin_id 和 col_role_id两个int列组成,并且每个int是4字节。通 过结果中的key_len=4可推断出查询使用了第一个列:col_admin_id列来执行索引查找
圖片.png
key_len计算规则

  • 字符串,char(n)和varchar(n),5.0.3以后版本中,n均代表字符数,而不是字节数,如果是utf-8,一个数字 或字母占1个字节,一个汉字占3个字节

char(n):如果存汉字长度就是 3n 字节
varchar(n):如果存汉字长度就是 3n+2 字节,加2个字节用来存储字符串长度

  • 数值类型
    • tinyint - 1字节
    • smallint - 2字节
    • int - 4字节
    • bigint - 8字节
  • 时间类型
    • date - 3字节
    • timestamp - 4字节
    • datetime - 8字节

注意:如果字段允许为 NULL,需要 1 字节记录是否为 NULL
_索引最大长度是768字节,当字符串过长时,mysql会做一个类似左前缀索引的处理,将前半部分的字符提取出来做索 引。

2.8、ref列

这一列显示了在key列记录的索引中,表查找值所用到的列或常量,常见的有:const(常量),字段名(例:film.id)

2.9、rows列

这一列是mysql估计要读取并检测的行数,注意这个不是结果集里的行数。

2.10、extra列

这列显示的是扩展信息,常见的重要值如下

  • Using index:使用覆盖索引

覆盖索引定义:整个查询结果只通过辅助索引就能拿到结果,不需要通过辅助索引树找到主键,再通过主键去主键索引树里获取其它字段值
圖片.png

  • Using where:使用 where 语句来处理结果,并且查询的列未被索引覆盖,需要优化

圖片.png
**

  • Using temporary:mysql需要创建一张临时表来处理查询。出现这种情况一般是要进行优化的,首先是想到用索 引来优化

圖片.png