SQL优化绕不开的字段explain,本篇文章研究一下explain时,一些常用字段基本含义,MySQL版本 5.7。
EXPLAIN SELECT diversion_code code,COUNT(*) c FROM
(SELECT user_id,MIN(create_time) create_time ,diversion_code FROM ct_diversion_user
GROUP BY user_id)r GROUP BY diversion_code
当我们使用一个稍复杂sql时,会出现如图所示基本条件列,那这些列代表什么?列里面的参数又有什么含义?
Explain中的列
id列
id列的值代表着sql语句执行的顺序,值越大,越优先执行
id列值都相等时,执行顺序为从上而下
select_type列
- simple:简单查询,只有自己一张表进行操作,不会关联其他表;
EXPLAIN SELECT *FROM ct_product WHERE id =32 ;
- primary:复杂查询中最外层的 select,语句中最后的查询层;
- subquery:在select(...)from之中的查询语句;
- derived:在select * from 之后的的查询语句;
- union:在union中后的select查询语句,但是在from后的查询语句中有union则为derived;
EXPLAIN
SELECT shop_id FROM ct_product UNION SELECT shop_id FROM ct_shop;
EXPLAIN
SELECT * FROM (SELECT shop_id FROM ct_product UNION all select 1) a
table列
EXPLAIN
SELECT * FROM (SELECT shop_id FROM ct_product UNION SELECT shop_id FROM ct_shop) a
- table列表式执行的哪一个表,当是<derivedN>时,id=N;
- table列的值为<union2,3>时,2、3为id列值,表式参与了union的有id=2行和id=3行;
type列
表示关联类型或访问类型。
type列常见值有system > const > eq_ref > ref > range > index > ALL ,SQL优化时,应将级别保证range以内,若能达到ref最好
当值为null时,意味着执行时不用再访问表或索引,结果直接得到,很少出现。
EXPLAIN SELECT min(id) FROM ct_product;
- system、const:意味着MySQL可以将SQL优化为常量查询,大多用于搜索条件是主键索引和唯一索引,索引查询出的结果只有一行结果,system是const的特例,当要查询的表里有且仅有一条数据时,当为system;
- eq_ref:两张表连接时,连接部分的主键索引和唯一索引的所有部分都被连接使用(一般不会出现);
- ref:使用普通索引或者唯一索引的部分前缀,可能出现多个值;
- range:范围扫描,多出现在in(),between,>,<等操作中;
- index:扫描全索引,一般扫描二级索引,然后得到主键索引,回表得到数据。这个级别比ALL好一点点,但不多;
- all:全表扫描,没有索引,或索引没有用。
possible_keys列
显示可能会走的索引,为null时,则认为没有要走的索引,或者是走的索引对查询帮助不大从而走了全表扫描。
key列
显示走的哪一个索引。
key_len列
显示索引里使用的字节数,可以通过计算得到索引中具体使用了哪些索引。
key_len计算规则如下:
字符串,char(n)和varchar(n),5.0.3以后版本中,n均代表字符数,而不是字节数,如果是utf-8,一个数字或字母占1个字节,一个汉字占3个字节
char(n):如果存汉字长度就是 3n 字节
varchar(n):如果存汉字则长度是 3n + 2 字节,加的2字节用来存储字符串长度,因为varchar是变长字符串
数值类型
tinyint:1字节
smallint:2字节
int:4字节
bigint:8字节
时间类型
date:3字节
timestamp:4字节
datetime:8字节
如果字段允许为 NULL,需要1字节记录是否为 NULL。
filtered列
该列是一个百分比的值,rows * filtered/100 可以估算出将要和 explain 中前一个表进行连接的行数(前一个表指 explain 中的id值比当前表id值小的表)。
Extra列
展示的是额外信息,仅供参考,不可作为依据。
- Using index:覆盖索引,一般用于二级索引,在二级索引中可直接得到想要得到的结果,不需要再回表查询原表。
#shop_id 为普通索引
select shop_id from ct_shop where shop_id='465546545646';
- Using where:使用 where 语句来处理结果,并且查询的列被全表扫描;
- Using index condition:查询的列不完全被索引覆盖,where条件中是一个前导列的范围;
- Using temporary:mysql:需要创建一张临时表来处理查询。出现这种情况一般是要进行优化的,首先是想到用索引来优化;
- Using filesort:将用外部排序而不是索引排序,数据较小时从内存排序,否则需要在磁盘完成排序。这种情况下一般也是要考虑使用索引来优化的。