MysqlExplain相关
explain能干什么:
- 表的读取顺序
- 数据读取操作的操作类型
- 哪些索引可以使用
- 哪些索引被实际使用
- 表之间的引用
- 每张表有多少行被执行
explain列分析:
id
select 查询的序列号,表示查询中执行select子句或操作表的顺序
三种情况:
- id相同,执行顺序由上至下
- id不同,id值越大优先级越高越先被执行
- id相同不同同时存在,id值越大优先级越高越先被执行,id如果相同,则从上往下顺序执行
这里注意 <derived[id]>,表示衍生表
select_type
用于说明查询类型,主要用于区别普通查询、联合查询、子查询等
有哪些值:
SIMPLE
简单的select查询,查询中不包含子查询或者union
PRIMARY
查询中若包含任何复杂的子部分,最外层查询则被标记为primary
explain
select t2.*
from t2
where id = (
select id
from t1
)
SUBQUERY
在select或where中包含的子查询,如上demo
DERIVED
在from子查询被标记为DERIVED,mysql会递归执行这些子查询,把结果放在临时表里
UNION
若第二个select出现在union之后,则被标记为union;
若union包含在from子句的查询子句中,外层select将被标记为:DERIVED
UNION RESULT
从union表获取结果的select
table
显示这一行数据是关于哪张表的
type
访问类型
system>const>eq_ref>ref>fulltext>ref_or_null>index_merge>unique_subquery>index_subquery>range>index>all
常用如下:
system>const>eq_ref>ref>range>index>all
system
当表中只有一行记录(等于系统表)并且该表使用的存储引擎的统计数据时精确的(比如MyISAM/Memory)。这是const类型的特例。
const
当使用主键或者唯一索引与常数进行等值匹配时,对单表的访问方法就是const。
explain
select * from (select * from t1 where id = 1) tt;
上条sql在mysql5.7的时候执行结果应该是下图:
我的mysql8的执行结果是下图(应该是mysql8在这种sql查询上做了优化):
eq_ref
在连接查询时,如果被驱动表是通过主键或者唯一二级索引列等值匹配的方式进行访问的(如果该主键或者唯一二级索引是联合索引的话,所有的索引列都必须进行等值比较),则对该被驱动表的访问方式就是eq_ref,如下demo:
create unique index t2_t1_id_uindex on t2 (t1_id);
explain
select * from t1 left join t2 on t1.id = t2.t1_id;
注意:这里t1.id是t1表的主键,t2.t1_id是t2表的唯一索引。
ref
当通过普通的二级索引列与常量进行等值匹配时来查询某个表,那么对该表的访问方法就可能是ref,如下demo:
explain
select * from t1 where single_idx = '1';
注意:这里t1.single_idx是t1表的普通单列索引。
ref_or_null
当对普通索引进行等值匹配查询并且该索引的列也可能是NULL的情况下,那么对该表的访问方法就可能是ref_or_null,如下demo:
explain
select * from t1 where single_idx = '1' or single_idx is null;
注意:这里t1.single_idx是t1表的普通单列索引。
index_merge
表示使用了索引合并优化。一般情况对于某个表的查询只能使用到一个索引,但在某些场景下可能会有索引合并的方式来执行查询。(MySQL5.0之前,一个表一次只能使用一个索引)
range
如果使用索引获取某些范围区间的记录,那么就可能使用到range。如下demo:
explain
select * from t1 where single_idx >2;
index
如果我有一个复合索引 t1 (column2, column3) 但是查询条件只用到了column3,这时候理论上是用不到索引的(最左前缀匹配)。但是,如果我的查询结果只有column2或者column2和column3的话,mysql就会用到该复合索引,当然是全索引扫描了。如下demo:
explain
select column2, column3 from t1 where column3 = 1;
ALL
全表扫描,性能最差
possible_keys
显示可能应用于这张表的索引,但不一定实际使用到。查询涉及到的字段若存在索引,则该索引将被列出。
key
实际使用到的索引,如果为null则表示没有使用索引。
key_len
索引中使用的字节数。在不损失精确度的情况下,长度越短越好。
key_len列表示当优化器决定使用某个索引执行查询时,该索引记录的最大长度,它由一下三部分组成:
- 对于使用固定长度类型的索引列来说,它实际占用的存储空间的最大长度就是该固定值。比如某个索引列的类型是VARCHAR(100),使用的字符集是utf8,那么该列key_len = 100 x 3 = 300。
- 如果该索引列可以存储NULL值,则key_len比不可以存储NULL值多1个字节。
- 对于变长字段来说,都会有2个字节的空间用来存储该变长列的实际长度。
复合索引可以通过key_len查看复合索引有哪几个列起作用。
ref
当使用索引列等值查询时,与索引列进行等值匹配的对象信息。
rows
根据表统计信息及索引选用情况,大致估算出所需读取的行数。
filtered
查询的表行占表的百分比。
Extra
包含不适合在其他列中显示但十分重要的额外信息
Using filesort
mysql中无法利用索引完成的排序,只能在内存(记录较少的时候)或者磁盘中(记录较多的时候)进行排序。这种操作称为"filesort"。
Using temporary
在许多查询的执行过程中,MySQL可能会借助临时表来完成一些功能,比如去重、排序之类的,比如我们在执行许多包含distinct、group by、union等子句的查询过程中,如果不能有效利用索引来完成查询,MySQL很有可能寻求通过建立内部的临时表来执行查询。如果查询中使用到了内部的临时表,在执行计划的Extra列将会显示Using temporary。如下demo:
explain
select column1, count(*) from t1 group by column1;
注意:column1没建索引。
Using index
表示select操作中使用了覆盖索引,避免访问聚簇索引的数据行,效率不错。
如果同时出现Using where,表明索引被用来执行索引键值的查找。
如果没有同时出现Using where,表明索引用来读取数据而未执行查找动作。
Using index condition
如果在查询语句的执行过程中使用到了索引下推则将会显示Using index condition,如下demo:
explain
select * from t1 where columnv > 'z' and columnv like '%a';
这里简单介绍一下索引下推[Index Condition Pushdown],上面sql先使用索引匹配columnv > ‘z’,但是like '%a’无法使用到索引。之前mysql版本处理方式是:1.先根据索引查询所有columnv > 'z’的主键值;2.然后根据主键回表,完了之后判断columnv like ‘%a’。可以但还能优化,优化方案是:1.先根据索引匹配columnv > ‘z’,然后判断columnv like ‘%a’,如果符合才拿主键去回表。这样可以减少回表操作。这也就是常说的索引下推。
Using where
当我们使用全表扫描来执行对某个表的查询,并且使用where查询时,会显示Using where。
Using join buffer
使用了连接缓存
impossible where
where 子句的值总是false,不能用来获取任何元组
distinct
Select tables optimized away
select操作已经优化到不能再优化了