MySQL | Explain的是使用详解_mysql

介绍

  1. Explain是SQL分析工具中非常重要的一个功能,可以模拟优化器执行查询语句,帮助我们理解查询是如何执行的;
  2. 分析查询执行计划可以帮助我们发现sql查询瓶颈,优化查询性能。

使用方法

  1. MySQL5.7 版本之前使用:
Explain Extended select * from user;
  1. MySQL5.7 版本开始:
Explain select * from user;
  1. 与show warnings搭配使用查看执行器优化后的sql:
Explain select * from user;
show warnings

返回详情

id

每个select都对应一个id,从1开始递增,如果该查询有子查询,将显示多个id值

id相同

执行顺序从上往下

id不同

序号大的先执行

同时存在

先执行序号大的,再从上往下

NULL

最后执行,且表示结果集,不需要使用它进行查询

select_type

SIMPLE

建单select,不包括union与子查询

PRIMARY

复杂查询中最外层查询,比如使用union和union all时,id为1的记录select_type通常是primary

SUBQUERY

指在select语句中出现的查询语句,结果不依赖于外部查询

DEPENDENT SUBQUERY

指在select语句中出现的查询语句,结果依赖于外部查询

DERIVED

派生表,在FROM子句的查询语句,标识从外部数据源中推导出来的,而不是从select语句中的其他列中选择出来的。

UNION

  1. 分union和union all两种,id大于1的select被标记为union;
  2. 如果union备from子句的子查询包含,则第一个select会备标记为derived;
  3. union会针对相同的结果集进行去重,union all不会进行去重处理;

DEPENDENT UNION

当union作为子查询时,其中第一个union为dependent subquery,第二个union为dependent union。

UNION RESULT

如果两个查询中有相同的列,则会对这些列进行重复删除,只保留一个表中的列。

UNCACHENABLE SUBQUERY

一个子查询的结果不能备缓存,而是需要每次查询时重新计算

table

查询所涉及的表名

  1. 如果有两个表,将显示多行记录。
  2. 如果有别名,展示别名。

partitions

表分区情况

type

查询访问类型

Null

MySQL在优化过程中分解语句就已经可以获取到结果,执行时甚至不用访问表或索引,效率高。

system

const类型的一种特殊场景,查询的表只有一行的情况

const

基于主键或唯一索引查看一行,当MySQL对查询某部分进行优化,并转换为一个常量时,使用这些类型访问转换成常量查询,效率高。

eq_ref

基于主键或唯一索引连接两个表,对于每个索引键值,只有一条匹配记录

ref

基于非唯一索引连接两个表,通过二级索引列与常量进行等值匹配,可能会存在多条匹配记录。

fulltext

全文索引

ref_or_null

基于非唯一索引连接两个表,通过二级索引进行等值匹配,该索引列的值可以是NULL值。

index_merge

标识使用索引合并的优化方法,当查询需要扫描大量的数据时,使用合并索引可以提高查询效率。

unique_subquery

查询使用合并索引来执行,当查询需要过滤大量数据时,使用子查询可以避免冲复航,从而提高查询效率。

index_subquery

查询使用子查询的索引,当查询需要过滤大量数据时,使用子查询可以提高查询效率,而使用索引可以提高查询性能。

range

使用非唯一索引扫描部分索引,比如使用索引获取某些范围区间的记录

index

扫描整个索引进行匹配

all

扫描整个表进行匹配

possible_keys

表示在查询中可能使用到某个索引或多个索引,如果没有选择索引,显示NULL

key

表示在实际在查询中使用的索引,如果没有使用索引,显示NULL

key_len

  1. 表示当优化器决定使用某个索引执行查询时,该索引记录的最大长度
  2. 作用:使用联合索引的时候可以知道使用了哪几列

计算规则

字符串
  • char(n):n个字节
  • varchar(n):如果是utf-8,3n+2个字节,加2字节存储字符串长度;若是utf8mb4:4n+2字节(变长字段:2字节)
数值类型
  • tinyint:1字节
  • smallint:2字节
  • int:4字节
  • bigint:8字节
时间类型
  • date:3字节
  • timestamp:4字节
  • datetime:8字节
空值字段:1字节
  • 如果字段是NULL,需要1个字节记录是否为NULL

ref

表示将哪个字段或常量和key列所使用的字段进行比较

rows

  1. 全表扫描时标识需要扫描标的行数估计值;
  2. 索引扫描时标识扫描索引的行数估计值;
  3. 值越小越好。

filtered

  1. 表示符合查询条件的数据百分比。
  2. 可以使用rows * friltered /100 计算出与explain前一个表进行连接的行数。

Extra

Using Index

仅使用索引树中的信息从表中检索列信息,不用进行其他查找就可以读取实际行。(覆盖索引:可查询列都是索引列)

Using Index condition

表示先按条件过滤索引,过滤完索引后找到所有符合索引条件的书巨航,随后用where子句中的其他条件去过滤这些书巨航。(使用索引范围查找,因查找列未备索引全覆盖,最终会回表查询)

Using where

不是读取表的所有数据或不通过索引奇偶可以获取所有需要的数据。(未使用索引检索数据)

Using temporary

标识MySQL需要使用临时表来存储结果集,如果查询包含不同列的GROUP BY和ORDER BY子句,通常会发生这种情况。(使用临时表存储数据进行数据去重等操作)

Using filesort

当查询中包含order by操作而且无法利用索引完成的排序操作,数据较少时从内存排序,如果数据较多需要在磁盘中排序,需优化成索引排序。(未使用索引进行排序导致在内存中或硬盘中排序)

Select tables optimized away

使用某些聚合函数(min,max)来访问某个索引值。(无需查找表、索引就可以返回数据,效率非常高)

Using join buffer

使用join buffer降低对被驱动表的扫描次数。

Impossible where

where子句是没有满足条件的目标数据,不会命中人何行。

No tables used

当此查询没有FROM子句或拥有FROM DUAL子句时出现。

Full scan on NULL key

子查询中的一种优化方式,在无法通过索引访问null值的时候使用。

最佳实践建议

全值匹配

  1. MySQL全值匹配是指在使用复合索引时,查询条件要包含索引的所有列,才能最大程度的去利用索引。
  2. 通俗点就是where条件里把该加的条件加上。

最左前缀法则

  1. 若索引了多列,我们需要遵守最左前缀法则。
  2. 查询从索引的最左前列开始并且不跳过索引中的列。

索引列不操作

  1. 不在索引列上任何操作,如计算、函数、类型转换等。
  2. 索引列操作会导致索引失效而变成全表扫描。

范围条件导致索引失效

  1. 存储引擎不能使用索引中范围条件右边的列。
  2. 范围查询会使后面字段无序,造成部分索引失效。
  3. mysql内部优化器根据检索比例、表大小等多个因素整体评估是否使用索引,可以将大的范围拆分成多个小范围。

多用覆盖索引

  1. 尽量使用覆盖索引,不用星。
  2. 即减少select *,多用select col1,col2

不等空值还有or,索引失效

  1. !=或<>
  2. is null或is not null
  3. or或in

like百分写最右

  1. 如like ‘%五’,有可能会导致全表扫描。
  2. 用写右方式,如like ‘王%’

多用union all,少用union

  1. union是去重并排序;union all直接返回合并的结果,不去重也不排序;
  2. union all比union性能好。

连接查询代替子查询

  1. 减少子查询,用连接查询代替子查询。
  2. 加索引,提高查询性能。

使用limit

  1. 避免过渡提取数据。
  2. 优化分页查询,简化查询结果。