介绍
- Explain是SQL分析工具中非常重要的一个功能,可以模拟优化器执行查询语句,帮助我们理解查询是如何执行的;
- 分析查询执行计划可以帮助我们发现sql查询瓶颈,优化查询性能。
使用方法
- MySQL5.7 版本之前使用:
Explain Extended select * from user;
- MySQL5.7 版本开始:
Explain select * from user;
- 与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
- 分union和union all两种,id大于1的select被标记为union;
- 如果union备from子句的子查询包含,则第一个select会备标记为derived;
- union会针对相同的结果集进行去重,union all不会进行去重处理;
DEPENDENT UNION
当union作为子查询时,其中第一个union为dependent subquery,第二个union为dependent union。
UNION RESULT
如果两个查询中有相同的列,则会对这些列进行重复删除,只保留一个表中的列。
UNCACHENABLE SUBQUERY
一个子查询的结果不能备缓存,而是需要每次查询时重新计算
table
查询所涉及的表名
- 如果有两个表,将显示多行记录。
- 如果有别名,展示别名。
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
- 表示当优化器决定使用某个索引执行查询时,该索引记录的最大长度
- 作用:使用联合索引的时候可以知道使用了哪几列
计算规则
字符串
- 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
- 全表扫描时标识需要扫描标的行数估计值;
- 索引扫描时标识扫描索引的行数估计值;
- 值越小越好。
filtered
- 表示符合查询条件的数据百分比。
- 可以使用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值的时候使用。
最佳实践建议
全值匹配
- MySQL全值匹配是指在使用复合索引时,查询条件要包含索引的所有列,才能最大程度的去利用索引。
- 通俗点就是where条件里把该加的条件加上。
最左前缀法则
- 若索引了多列,我们需要遵守最左前缀法则。
- 查询从索引的最左前列开始并且不跳过索引中的列。
索引列不操作
- 不在索引列上任何操作,如计算、函数、类型转换等。
- 索引列操作会导致索引失效而变成全表扫描。
范围条件导致索引失效
- 存储引擎不能使用索引中范围条件右边的列。
- 范围查询会使后面字段无序,造成部分索引失效。
- mysql内部优化器根据检索比例、表大小等多个因素整体评估是否使用索引,可以将大的范围拆分成多个小范围。
多用覆盖索引
- 尽量使用覆盖索引,不用星。
- 即减少select *,多用select col1,col2
不等空值还有or,索引失效
- !=或<>
- is null或is not null
- or或in
like百分写最右
- 如like ‘%五’,有可能会导致全表扫描。
- 用写右方式,如like ‘王%’
多用union all,少用union
- union是去重并排序;union all直接返回合并的结果,不去重也不排序;
- union all比union性能好。
连接查询代替子查询
- 减少子查询,用连接查询代替子查询。
- 加索引,提高查询性能。
使用limit
- 避免过渡提取数据。
- 优化分页查询,简化查询结果。