先来看下explain效果
explain select * from django_session;
expain出来的信息有12列,分别是id、select_type、table、type、partiyions(mysql5.7新增)、possible_keys、key、key_len、ref、rows、filtered(mysql5.7新增)、Extra,下面对这些字段出现的可能进行解释:
1、ID
1) 如果是子查询,id的序号会递增,id值越大优先级越高,越先被执行
2)id如果相同,可以认为是一组,从上往下顺序执行;在所有组中,id值越大,优先级越高,越先执行
3)id可以为空
2、select_type表示查询中每个select子句的类型
(1) SIMPLE(简单SELECT,不使用UNION或子查询等)
(2) PRIMARY(查询中若包含任何复杂的子部分,最外层的select被标记为PRIMARY)
(3) UNION(UNION中的第二个或后面的SELECT语句)
(4) DEPENDENT UNION(UNION中的第二个或后面的SELECT语句,取决于外面的查询)
(5) UNION RESULT(UNION的结果)
(6) SUBQUERY(子查询中的第一个SELECT)
(7) DEPENDENT SUBQUERY(子查询中的第一个SELECT,取决于外面的查询)
(8) DERIVED(派生表的SELECT, FROM子句的子查询)
(9) UNCACHEABLE SUBQUERY(一个子查询的结果不能被缓存,必须重新评估外链接的第一行)
三、table
显示这一行的数据是关于哪张表的,join或者嵌套查询时不是真实表名称,看到的是derivedx(x是个数字,可以简单理解为第几步执行的结果)
比如:
mysql> explain select * from (select * from ( select * from t1 where id=2602) a) b;
+----+-------------+------------+--------+-------------------+---------+---------+------+------+-------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+------------+--------+-------------------+---------+---------+------+------+-------+
| 1 | PRIMARY | <derived2> | system | NULL | NULL | NULL | NULL | 1 | |
| 2 | DERIVED | <derived3> | system | NULL | NULL | NULL | NULL | 1 | |
| 3 | DERIVED | t1 | const | PRIMARY,idx_t1_id | PRIMARY | 4 | | 1 | |
+----+-------------+------------+--------+-------------------+---------+---------+------+------+-------+
四、type
表示MySQL在表中找到所需行的方式,又称“访问类型”。
常用的类型有: ALL, index, range, ref, eq_ref, const, system, NULL(从左到右,性能从差到好)
ALL:Full Table Scan, MySQL将遍历全表以找到匹配的行
index: Full Index Scan,index与ALL区别为index类型只遍历索引树
range:只检索给定范围的行,使用一个索引来选择行
ref: 表示上述表的连接匹配条件,即哪些列或常量被用于查找索引列上的值
eq_ref: 类似ref,区别就在使用的索引是唯一索引,对于每个索引键值,表中只有一条记录匹配,简单来说,就是多表连接中使用primary key或者 unique key作为关联条件
const、system: 当MySQL对查询某部分进行优化,并转换为一个常量时,使用这些类型访问。如将主键置于where列表中,MySQL就能将该查询转换为一个常量,system是const类型的特例,当查询的表只有一行的情况下,使用system
NULL: MySQL在优化过程中分解语句,执行时甚至不用访问表或索引,例如从一个索引列里选取最小值可以通过单独索引查找完成。
五、possible_keys
指出MySQL能使用哪个索引在表中找到记录,查询涉及到的字段上若存在索引,则该索引将被列出,但不一定被查询使用
该列完全独立于EXPLAIN输出所示的表的次序。这意味着在possible_keys中的某些键实际上不能按生成的表次序使用。
如果该列是NULL,则没有相关的索引。在这种情况下,可以通过检查WHERE子句看是否它引用某些列或适合索引的列来提高你的查询性能。如果是这样,创造一个适当的索引并且再次用EXPLAIN检查查询
六、Key
key列显示MySQL实际决定使用的键(索引)
如果没有选择索引,键是NULL。要想强制MySQL使用或忽视possible_keys列中的索引,在查询中使用FORCE INDEX、USE INDEX或者IGNORE INDEX。
七、key_len
表示索引中使用的字节数,可通过该列计算查询中使用的索引的长度(key_len显示的值为索引字段的最大可能长度,并非实际使用长度,即key_len是根据表定义计算而得,不是通过表内检索出的)
不损失精确性的情况下,长度越短越好
当用到组合索引的时候判断索引是否完全用上。
实例:假设student表中有字段
id int
name char(20) DEFAULT NULL
address varchar(20) DEFAULT NULL
remark varchar(20) NOT NULL
建立的索引是 idx_address_remark(在address和remark上建立的组合索引)
查询的sql是:select * from student where address='北京' and remark='Python coder',此时,执行计划中的key_len是 (20*3+1+2)+ (20*3+2)= 125,那么这个是怎么得来的呢?
解析:20表示建表的时候 varchar(20) ,3表示utf8字符集占用3个字节,1表示MySQL需要1个字节表示null,2表示变长字段(varchar是变长的)。
假设drop掉刚刚建立的索引,新建索引 idx_name_address(在name和address上建立组合索引)
查询的sql是:select * from student where name='Spencer' and address='北京',此时,执行计划中的key_len是 (20*3+1)+ (20*3+2)= 123,那么这个值是怎么得来的呢?
解析:20表示建表的时候 char(20) ,3表示utf8字符集占用3个字节,1表示MySQL需要1个字节标识null,即 20*3+1,后面的同样的道理。
key_len只计算where条件用到的索引长度,而排序和分组就算用到了索引,也不会计算到key_len中。
计算key_len的公式:
varchr(10)变长字段且允许NULL = 10 * ( character set:utf8=3,gbk=2,latin1=1) + 1(NULL) + 2(变长字段)
varchr(10)变长字段且不允许NULL = 10 *( character set:utf8=3,gbk=2,latin1=1) + 2(变长字段)
char(10)固定字段且允许NULL = 10 * ( character set:utf8=3,gbk=2,latin1=1)+1(NULL)
char(10)固定字段且不允许NULL = 10 * ( character set:utf8=3,gbk=2,latin1=1)
八、ref
表示上述表的连接匹配条件,即哪些列或常量被用于查找索引列上的值
九、rows 表示MySQL根据表统计信息及索引选用情况,估算的找到所需的记录所需要读取的行数
十、Extra
该列包含MySQL解决查询的详细信息,但是此字段的部分值具有优化的参考意义。有以下几种情况:
Using where:列数据是从仅仅使用了索引中的信息而没有读取实际的行动的表返回的,这发生在对表的全部的请求列都是同一个索引的部分的时候,表示mysql服务器将在存储引擎检索行后再进行过滤using index:表示使用了覆盖索引。这个值重点强调了只需要使用索引就可以满足查询表的要求,不需要直接访问表数据。
using temporary:mysql需要创建一张临时表来保存中间结果,常见于排序和分组查询。 也就是说,需要先把数据放到临时表中,然后从临时表中获取需要的数据。出现这种临时表,也是必须需要优化的地方,特别是数据量大的情况。两个常见的原因是在来自不同表的列上使用了distinct,或者使用了不同的 order by 和 group by 列。
Using filesort:这是 order by 语句的结果,MySQL中无法利用索引完成的排序操作称为“文件排序”,这可能是一个CPU密集型的过程。using filesort表示出现了文件内排序,表示很不好的现象,必须要优化,特别是大表,可以通过选择合适的索引来改进性能,用索引来为查询结果排序。
Using join buffer:改值强调了在获取连接条件时没有使用索引,并且需要连接缓冲区来存储中间结果。如果出现了这个值,那应该注意,根据查询的具体情况可能需要添加索引来改进能。
Impossible where:这个值强调了where语句会导致没有符合条件的行。
Select tables optimized away:这个值意味着仅通过使用索引,优化器可能仅从聚合函数结果中返回一行
十一、partitions(mysql5.7新增)
使用的哪个分区,需要结合表分区才可以看到
如果想在mysql5.5查看,可以使用:
explain extended select ....
十二、filtered(mysql5.7新增)
通过过滤条件之后对比总数的百分比
给出了一个百分比的值,这个百分比值和rows列的值一起使用,可以估计出那些将要和执行计划中的前一个表(前一个表就是指id列的值比当前表的id小的表)进行连接的行的数目。
这一列在5.5版本中,需要加上
explain extended select ....