explain:mysql分析优化工具
explain能解释mysql如何处理SQL语句,表的加载顺序,表是如何连接,以及索引使用情况。是SQL优化的重要工具
在select语句之前增加 explain 关键字,MySQL 会在查询上设置一个标记,执行查询会返回执行计划的信息,而不是执行这条SQL
如果 from 中包含子查询,仍会执行该子查询,将结果放入临时表中。
Explain extended看起来和正常的explain行为一样,但它会告诉服务器"逆向编译"执行计划为一个select语句。可以通过紧接其后运行showwarnings看到这个生成的语句。这个语句直接来自执行计划,而不是原SQL语句,到这点上已经变成一个数据结构。大部分场景下,它都是优化过的,跟原语句不相同,可以学习查询优化器到底是如何转化语句的
Explain partitions会显示查询将访问的分区,如果查询是基于分区表的话。一般认为增加explain时,MySQL语句不会执行查询,这是错误的。如果查询在from子句中包括子查询,那么MySQL实际上是会执行子查询,将其结果放在一个临时表中,然后完成外层查询优化。
原表结构
原表数据
执行查询语句 查找price=30的所有数据
sql
SELECT * FROM test_db WHERE price = 30
可以看到只有一条数据
用explain语句来分析下本次查询是否命中索引
sql
EXPLAIN SELECT * FROM test_db WHERE price = 30;
可以看到出现了一行数据
字段含义
id
id表示执行select查询语句的序号,它是sql执行的顺序的标识,sql按照id从大到小执行,id相同的为一组,从上到下执行。例如使用联表和多表查询的时候,sql的查询顺序
id相同情况:
sql
EXPLAIN SELECT * FROM user_db WHERE id in (SELECT id FROM test_db WHERE id = 1);
则这里的多表查询,id相同,先执行user_db,后执行test_db
id不同情况:
sql
EXPLAIN SELECT * FROM user_db WHERE id = (SELECT id FROM test_db WHERE id = 1);
id大的先执行,所以先执行user_db的查询,后执行test_db的查询
select_type
select_type表示查询的类型,也就是对应的是简单查询还是复杂查询
simple
简单查询,不包括复杂的语句,多表查询也可以可以有JOIN连接
简单查询
sql
select * from user_db where user_name = "test_t";
多表查询用join
sql
SELECT * FROM user_db JOIN test_db on user_db.id = test_db.id
sql
EXPLAIN SELECT * FROM user_db JOIN test_db on user_db.id = test_db.id;
可以看到select_type都是simple
primary
包含多个查询语句
子查询(in):
sql
EXPLAIN SELECT * FROM user_db WHERE id in (SELECT price FROM test_db WHERE name = "3") or id =3;
这里primary指的是最左边执行查询的表
union
sql
EXPLAIN SELECT id FROM user_db WHERE id =3 union SELECT id FROM test_db WHERE id = 3;
使用union查询需保证字段一致和结构一致
primary指的是在最左边执行查询的表
其余的均标记为union
union
sql
EXPLAIN SELECT id FROM user_db WHERE id =3 union SELECT id FROM test_db WHERE id = 3;
使用union查询需保证字段一致和结构一致
其余的均标记为union
UNION RESULT
UNION使用临时表进行去重,标记临时表的查询为UNION RESULT
SUBQUERY
在**「select或者where中包含的子查询」**会被表示为SUBQUERY类型
sql
EXPLAIN SELECT * FROM user_db WHERE id in (SELECT price FROM test_db WHERE name = "3") or id =3;
DERIVED
「DERIVED表示的是派生表或者衍生表的意思,在from包含的子查询中会被表示为DERIVED类型」,Mysql会递归执行这些子查询,并且把结果放在临时表中。
在8.0之后的版本很难出现这类情况
sql
EXPLAIN SELECT * FROM (SELECT * FROM test_db where id>1) a where a.price=1;
DEPENDENT SUBQUERY(依赖性子查询)
只要出现了DEPENDENT 关键字,就表示是依赖性查询,依赖指的是依赖于主查询。该字段出现表示是出现了相关子查询,意思是子查询里面的表要依赖于主查询中的数据。
sql
EXPLAIN SELECT id FROM user_db WHERE id =(SELECT id FROM test_db WHERE id=user_db.id);
UNCACHEABLE UNION(未被缓存的查询)
该字段出现表示查询出来的结果不能放到缓存中。出现于子查询里面又有一个union查询,但是union后面的那张表(goods_db)和主查询中的表(test_db)没有联系的情况。
sql
EXPLAIN SELECT id FROM test_db WHERE id =(SELECT id FROM user_db WHERE id=test_db.id union select id from goods_db where user_id = 30);
DEPENDENT UNION(依赖性联合查询)
表示子查询里面出现了union查询,但是union后面的那张表和主查询有联系。
sql
EXPLAIN SELECT id FROM test_db WHERE id =(SELECT id FROM goods_db WHERE id=30 union select id from user_db where id = test_db.id);
UNCACHEABLE SUBQUERY(未被缓存的子查询)
表示子查询里面出现了子查询,但是子查询的表和主查询无联系。
sql
EXPLAIN SELECT id FROM test_db WHERE id =(SELECT id FROM goods_db WHERE id=30 union select id from user_db where id = test_db.id);
table
这一列表示 explain 的一行正在访问哪个表。
如果出现了 <derived 数字>,表示是用到了衍生表,数字是该表出现的顺序
type
它显示了该select SQL使用了何种方式进行查询
性能从好到差依次是: system、const、eq_ref、ref、range、index、all
system:表中只有一条数据
const:从表中通过常量只查询出一条数据,并且这条数据是通过主键索引或者唯一索引来查询出来的。
sql
EXPLAIN SELECT * FROM test_db where id=30;
eq_ref:唯一性索引,对于要查询的字段,只返回匹配唯一的一行数据,有且只能有一个,在唯一索引和主键索引上
sql
EXPLAIN SELECT id FROM test_db WHERE id =(SELECT id FROM goods_db WHERE id=30 union select id from user_db where id = test_db.id);
这里user_db用到了唯一性索引,id为主键索引而且自增不唯一
ref
非唯一性索引,对于索引的查询,可以返回0个或多个
range
执行索引查询的范围,使用between、>、<、in
index
使用index表示从当前索引树(B+树)来进行查询
All
表示全表扫描
Possible_keys
这一列显示理论上应该可能用到的索引有哪些,这个数量最好和select 后面查询的字段数量是一致的。如果使用了索引,但是没有出现在该列中,则说明该SQL使用的是覆盖索引。如果为null,表示没有用到索引。
key
实际用到的索引
key_len
索引长度,单位字节
为了可以节约空间,索引长度小点更好
ref
表示用到了哪个表的哪个字段
sql
EXPLAIN SELECT id FROM test_db WHERE id =(SELECT id FROM goods_db WHERE id=30 union select id from user_db where id = test_db.id);
可以看到第三张表user_db用到了test_db这张表
第二张表goods_db为const,即where的查询条件为常量
rows
通过索引查到的数据个数,即通过索引查询找到的数据行数
extra
其它的重要字段
Using filesort
查询过程中需重新查询一次,查询id之后还的再次查询price以根据price来排序
sql
EXPLAIN SELECT id FROM test_db order by price;
Using temporary
开辟了临时表,性能损耗大,常见于group by语句
sql
EXPLAIN SELECT max(price) FROM test_db group by price;
using index
表示使用到了覆盖索引,不用进行回表查询
sql
EXPLAIN SELECT id FROM test_db WHERE id =(SELECT id FROM goods_db WHERE id=30 union select id from user_db where id = test_db.id);
其中第二、三张表都使用了覆盖索引
using where
需回表查询