explain
这是这次想要了解的重点命令,用于查看mysql
中查询sql语句的执行计划,用来对sql进行优化,以最合理的方式写sql语句
一条标准的sql查询语句:
explain select id from user_customer where id=1\G;
得到的结果:
*************************** 1. row ***************************
id: 1
select_type: SIMPLE
table: user_customer
partitions: NULL
type: const
possible_keys: PRIMARY
key: PRIMARY
key_len: 4
ref: const
rows: 1
filtered: 100.00
Extra: Using index
从上面可以看到所有的参数,下面一一进行说明:
id
select查询的标识符,每个select都会被自动分配一个唯一的标识符
select_type
select 查询的类型,常见的值如下:
SIMPLE:表示此查询不包含UNION查询或子查询
PRIMARY:表示此查询是最外层的查询
UNION:表示此查询是UNION的第二或随后的查询
DEPENDENT UNION:UNION中的第二个或后面的查询语句,取决于外面的查询
UNION RESULT:UNION的结果
SUBQUERY:子查询中的第一个SELECT
DEPENDEND SUBQUERY:子查询中的第一个SELECT,取决于外面的查询,即子查询依赖于外层查询的结果
DERIVED:被驱动的select子查询(子查询位于FROM子句)
MATERIALIZED:被物化的子查询
table
查询涉及到的数据表或衍生表
type
type
字段比较重要,它标识了查询是否高效,是使用了全表扫描
还是索引扫描
等等
system:表中只有一条数据,这个类型是特殊的const类型
const:针对主键或唯一索引的等值查询扫描,最多只返回一条数据。const查询的速度非常快,因为它仅仅读取一次即可,如下面的sql语句
select * from user_customer where id=5;
ref:此类型通常出现在多表的join查询,针对于非唯一或非主键索引,或者是使用了
最左前缀
规则索引的查询
select * from user_customer where first_name='123' and last_name='456';
explain select * from migrations,user_customer where migrations.batch=user_customer.uid and cid>1\G;
eq_ref:通常出现在多表的join查询,对于对于前表的每一个结果,都只能匹配到后表的一行结果,并且查询的比较操作是=
,查询效率较高
explain select * from migrations,user_customer where migrations.batch=user_customer.uid \G; //前表的数据在后表中都有匹配
range:range表示的索引范围查找,通过索引字段范围获取表中部分数据记录,这个类型通常出现在
=
,<>
,>
,<
,between
,in()
等操作中
当type
是range
时,那么explain
输出的ref
字段为NULL,并且ken_len
字段为此次查询中使用到的索引的最长的那个> int的长度是4字节,bigint的长度是8字节;字符串根据字段的长度可以计算出长度(**utf每个字符占用3字节,如果是varchar**);如果字段允许null则会增加一个字节的大小
index:表示扫描的时候仅仅扫描了索引,而不扫描数据;也就是说在查询数据的时候直接在索引树中就可以获取到,在这种情况下的时候,extra字段会显式
Using Index
all:表示全表扫描,是所有这些属性中性能最差的一个
type类型的性能比较
all < index < range ~ index_merge < ref < eq_ref < const < system
possible_keys
表示在查询的过程中有可能使用到的keys
ken_len
表示查询优化器使用到了的索引的字节数,这个字段可以评估出组合索引是否被完全使用到,或只有最左部分字段被使用到,key_len
的计算规则如下:
字符串
char(n):固定长度,n字符长度,根据不同的编码n2或n3的字节
varchar(n):变长长度,在实际计算存储大小的时候,n小于255则用1字节存储长度,大于255则用2字节存储长度
数值类型
tinyint(n):1字节
smallint(n):2字节
mediumint(n):3字节
int(n):4字节
bitint(n):8字节
时间类型
date:3字节
timestamp:4字节
datetime:8字节
字段属性:
Null属性占用一个字节,如果字段是NOT NULL的,则不会占用这额外的一字节
在数值类型中,是预留出了一位去存储数值的符号
rows
mysql查询优化器根据统计信息,估算sql要查找结果集需要扫描读取的数据行数,这个值可以直观的反映出sql的效率,原则上rows数值越小越好
extra
在sql中很多额外的信息会在extra字段中体现:
Using filesort
当Extra字段中有Using filesort
时,表示mysql需要额外的排序操作,不能通过索引顺序达到排序效果;在sql语句中使用order by
进行排序的时候,如果没有很好的使用到定值和最左排序的话,会出现这种情况Using index condition
这是mysql5.6的新特性,叫
索引条件推送
,只是针对于二级索引。在一般情况下,mysql服务器都会将存储引擎处理完成的数据返回给服务层后在应用where条件进行过滤,但是当mysql筛选到where条件中的第一个条件筛选的方式是类似于范围查询,就是
like
,<
等;但是这里mysql的查询优化器会筛选第一个where条件中的能够查询出的范围,会根据range的范围与数据的总数进行对比进行什么样的查询查询想要获取的字段都是
*
Using index
“覆盖索引扫描”,表示查询在索引树上就可以找到所需要的数据,而不需要扫描底层的叶子节点数据,这种情况性能很好
只出现了这个的时候表示性能很好;如果这个和Using where
同时出现的话,表示先在存储引擎中使用索引进行筛选,再在mysql服务中进行条件筛选
Using temporary
在查询的时候使用临时表,一般出现排序,分组和多表join的情况,查询效率不高,建议进行优化Using where
使用了where从句来限制哪些行将与下一个表匹配或者是返回给用户
Extra列出现Using where表示mysql服务器将存储引擎返回服务层以后再应用where条件过滤
有一种情况,数据表中数据量很大,查询的条件在数据表中占的比例也很高,本来在原则上可以使用索引,但是因为该查询记录占表中比例很大,mysql会不对该sql使用索引,这种情况可以在查询语句后面使用limit
进行限制
Using MRR
这也是mysql5.6新增的特性, Multi-Range Read(多范围读),针对基于辅助/第二索引的查询,减少随机IO,并且将随机IO转换为顺序IO,提高查询效率
在基于mysql中的Innodb的数据存储方式才用的是B+tree
,二级索引的存储顺序与主键的顺序是不一致的,开启了mrr之后,mysql将根据辅助结果集获取的结果集根据主键进行排序,将乱序化为有序,可以用主键访问基表,将随机读转换为顺序读,多页数据记录可一次性读入或根据此次的主键范围分次读入,以减少IO操作,提高查询效率
Not exists
mysql优化了left join
,一旦它找到了匹配left join标准的行,就不再搜索了