这是我参与8月更文挑战的第三天。
通过Explain关键字可以更透彻的来解析一条查询的SQL,以便进行后续的优化,使用方法是在一条select 查询前面加上 Explain,然后执行。
当执行一条查询语句的时候,使用explain会展现出 12 列数据,下面来逐一分析每一列数据包含的含义。
id列
这一列总是会包含一个编号,编号越大表示该行数据越先执行,如果编号一样,则会从上往下依次执行。
下面是id相同的情况,会从上往下依次执行,会优先执行 t_course表,因为t_course表的数量比t_test表要少,mysql会优先执行数据量少的表。
下面是id不相同的情况,会先执行id大的表,也就是会先执行子查询里面的内容。
select_type列
这一列总是会包含一个编号,它分为6种情况:SIMPLE、PRIMARY、SUBQUERY、DERIVED、UNION、UNION RESULT
SIMPLE(简单查询)
simple就是简单的一个查询,不会包含任何子查询和UNION。
PRIMARY(主查询)、SUBQUERY(子查询)
如果出现了子查询,则主查询为PRIMARY,子查询为SUBQUERY,但是只限制是select 或者where后面出现的子查询。
DERIVED(派生查询)
DERIVED表示子查询出现在from语句的后面。在mysql8.0很难出现DERIVED,下面是mysql 5.6.47版本测试的结果。
UNION(联合查询)、UNION RESULT(联合结果的查询)
UNION表示的是第二个select查询所在的表。UNION RESULT表示对 union查询产生的这个临时表做查询操作。
DEPENDENT SUBQUERY(依赖性子查询)
只要出现了DEPENDENT 关键字,就表示是依赖性查询,依赖指的是依赖于主查询。该字段出现表示是出现了相关子查询,意思是子查询里面的表要依赖于主查询中的数据。
UNCACHEABLE UNION(未被缓存的查询)
该字段出现表示查询出来的结果不能放到缓存中。出现于子查询里面又有一个union查询,但是union后面的那张表(t_course)和主查询中的表(t_test)没有联系的情况。
DEPENDENT UNION(依赖性联合查询)
表示子查询里面出现了union查询,但是union后面的那张表和主查询有联系。
table列
这一列显示了对应行正在访问哪个表,如果该表起了别名,显示的就是表的别名。
如果出现了<union 数字1,数字2>,则表示查询出的结果是通过union 联合前两张表(第一张,第二张)查出来的。
如果出现了 <derived 数字>,表示是用到了衍生表,数字是该表出现的顺序
type列
这一列和最后一列Extra是查询SQL性能的核心,它显示了该select SQL使用了何种方式进行查询,粗略的来说,一共有8种,性能从好到差依次是: system、const、eq_ref、ref、range、index、all。 在我们日常开发中,前三个基本是达不到的,最好可以达到ref级别。前提是需要有索引。
system
表中只有一条数据,这种情况基本达不到,只是理想的情况。它是const类型的一个特例。
const
从表中通过常量只查询出一条数据,并且这条数据是通过主键索引或者唯一索引来查询出来的。
eq_ref
唯一性索引,对于要查询的字段,只返回匹配唯一的一行数据,有且只能有一个(不能多个,也不能为0),比如姓名这一列不能出现重名的,所以还是经常出现在唯一索引和主键索引上。(该字段在mysql 8.0版本测试很不稳定,没有特别准确的例子,下图是msyql 5.7版本)
ref
非唯一性索引,对于索引的查询,可以返回0个或多个
t_student表中有两个名字为‘zs’的值
range
执行索引查询的范围,使用between、>、<、in,但是有时候会失效
index
表示从当前索引树来进行查询,比全表扫描要好一些。
All
表示全表扫描,没有使用到索引,效率最低。
Possible_keys 列
这一列显示理论上应该使用的索引有哪些,这个数量最好和select 后面查询的字段数量是一致的。如果使用了索引,但是没有出现在该列中,则说明该SQL使用的是覆盖索引。
key列
该SQL实际用到的索引。
key_len列
表示索引中使用的字节数,可通过该列计算查询中使用的索引长度,在不损失精确性的情况下,长度越短越好。Key_len显示的值为索引字段的最大可能长度,并非实际使用长度,是根据表定义计算而得,不是通过表内检索出的。key_len可以表示精度,精度越高,长度就越长,意味着代价也就越大。
ref列
表示用到了哪个表的那一列索引。如果这个表的一列使用的是常量,则为const。
rows列
通过索引查到的数据个数,根据表统计信息及索引选用情况,大致估算出找到所需记录所需要读取的行数。越少越好。
extre列
包含不适合在其他列中显示但十分重要的额外信息。如果出现了filesort不是特别好,表示它使用了外部的索引排序,而不是按照表内的索引顺序进行读取。如果出现了temporary更不好,表示出现了一张临时表;常见于排序order by 和分组查询 group by 使用临时表是很耗费性能的,因为创建之后就需要回收,出现了using index是好事,如果同时出现了usingwhere ,表明索引被用来执行索引键值的查找;如果没有同时出现using where,表明索引用来读取数据而非执行查找动作。
出现了using filesort表示需要额外的一次排序,举例:
#不需要重排序,因为已经查出了name,然后根据name排序,有先后关系
select name from table1 order by name
#需要重排序,因为已经查出了name,然后根据age排序,所以需要查询出age,然后再重新排序。
select name from table1 order by age
出现了using temporary,表示性能损耗更大,用到了临时表,一般出现在group by语句中。
#不会出现temporary
select * from table1 where name = "zhangsan" group by name
#会出现temporary,age 需要一张新的表
select * from table1 where name = "zhangsan" group by age