通常都会使用Explain来查看sql的执行计划,快速的分析sql性能并找出sql的问题所在。
explain执行计划的结果有一下列:
id | select_type | table | type | possible_keys | key | key_len | ref | rows | extra
说明:
id: select查询的序列号,包含一组数字,表示执行select字句或操作表的顺序。
1.如果id相同,则执行顺序由上至下
2.如果id不同,且有子查询,则id越大的执行优先级越高。因为子查询都是需要先查询子查询里面的值,然后再执行子查询外面的普通查询。
3.如果id有相同的也有不同的,则id越大的执行优先级越高,然后相同id的按自上而下的优先级执行。(可以认为id相同的为同一组,同一组自上而下执行)
select_type: 用于区别普通查询,联合查询,子查询等复杂的查询;常见的值有 SIMPLE,PRIMARY,SUBQUERY,DERIVED,UNION,UNION RESULT
1.SIMPLE 表示简单查询,不包含子查询或UNION
2.PRIMARY 查询中若包含任何复杂的子查询,最外层查询则被标记为PRIMARY
3.SUBQUERY 表示select或where中的子查询
4.DERIVED 在from列表中包含的子查询被标记为DERIVED(衍生),mysql会递归执行这些子查询,把结果放到临时表里
5.UNION 第二个select出现在union之后,则被标记为UNION;如果UNION包含在from字句的子查询中,外层select将被标记为DERIVED
6.UNION RESULT 是两个表union的结果会被标记为UNION RESULT
type 访问类型,表示查询使用了哪种类型进行查询,性能由好到差依次为:simple>const>eq_ref>ref>range>index>ALL; 如果进行了优化,则要求最少达到ref或range,如果到simple则是最好。
1. system 只有一行记录(等同系统表),这是const类型的特例,一般不会出现。
2.const 通过索引一次就找到了,const用于比较primary key 或unique索引。因为只匹配一行数据,所以很快。如将主键放到where的查询条件中,就会走const
3.eq_ref 唯一性索引扫描,对于每个索引键,表中只有一条记录与之匹配。常见于主键或唯一索引扫描。如inner join,left join 联表查询时,一张表根据主键或者唯一索引之后只有一条记录(根据on条件查询)。如单表中查询根据身份证号码查询,只能查询出一行数据。
4.ref 非唯一性索引扫描,返回匹配的多行记录。如inner join, left join 联表查询时,根据on条件能够查询出多条相同的数据。如单表查询中直接根据姓名查询出多行相同的数据。
5.range 只检索给定范围的行,使用一个索引来选择行。一般都是where中有 <, > between, in 等范围查询条件。
6.index 索引扫描,select条件中只要包含了索引列,则会是index索引扫描,索引扫描比ALL全文扫描性能好。
possible_keys 显示表中可能使用到的索引,一个或多个。但不一定被查询实际使用。
key 表示实际上用到的索引。如果为null,则没有使用索引。查询中如果使用了覆盖索引(即查询的字段与索引的字段相同),则该索引仅出现在key列中。
key_len 表示索引中使用的字节数,可通过该列计算查询中的索引长度。在不损失精确性的情况下,长度越短越好。key_len显示的值为索引字段的最大可能长度,并非实际使用长度,即key_len是根据表定义计算得到的,而不是表内检索得到的。(即例如索引为一个字段时,查询的where条件为一个字段(索引)时的效率比多个字段(其中一个为索引字段)的效率高,因为一个字段的长度短于多个字段的长度)
ref 显示索引的哪一列被使用了,如果可能,是一个常数。通常都是列名。
rows 表示索引之后查询出的行数,越小越好。
extra 执行计划中的一些其他信息,常见的有以下值,其他值请参考官方文档。
1.using filesort 查询重排序,通常出现在已经建立了索引,但是查询条件中包含order by 排序,且排序字段与组合索引的顺序不一致。如果出现了using filesort 则表明查询速度变慢。例如组合索引a,b,c. 然后查询select * from table order by c。需要优化为select * from table order by a,b,c
2.using temporary 使用临时表来存储结果。常见于排序和分组查询。group by语句。mysql使用了临时空间来存放结果,结果使用完又需要释放,这样的效率比起无需使用临时空间暂存结果的效率低。能够避免就尽量避免。
3.using index 效率非常高,通常是查询的字段与索引字段一样。直接使用了索引进行查询,无需回表查询。如果我们不是读取表的所有数据,或者不是仅仅通过索引就可以获取所有需要的数据,则会出现using where信息。
小结:type/key/rows/extra 这4列内容最为重要,type能够看出索引的效率高低。key可以帮助我们判断如果是走了索引情况下是走哪个索引。rows可以帮助我们判断本次sql过滤的行数,行数越小效率越高。 extra的值如果是using filesort或using temporary则表明sql需要优化。
--------------------------------------------------------------------------------------------------------------------------------------
2022年5月29日:
关于key_len的补充说明:表示索引使用的字节数,根据这个值可以判断索引的使用情况,特别是在组合索引的时候,判断该索引有多少部分被使用到非常重要。比如一个组合索引有3个字段(a,b,c)。如果命中了1个字段key_len的长度可能为10,命中了2个字段key_len的长度可能为20,命中3个字段长度可能为30。当索引字段确定时,命中的字段越多,key_len越大。不能单纯的以为key_len越大命中的索引字段越多,比如字段a是varchar类型的,长度为500。字段b是varchar类型的长度只是50,如果分别命中了a,b两个字段,则key_len的长度当然是a的大。如果这时候多了一个字段c是varchar类型的长度是10。如果命中了索引a和索引(b,c)这两种场景,看到的key_len当然是a的大。但这时候实际上也还是(b,c)索引效率更高。