EXPLAIN关键字可以模拟MySQL优化器执行SQL语句,学会解释EXPLAIN将帮助你了解MySQL优化器是如何工作的。
EXPLAIN输出列
列 | 含义 |
---|---|
id | select查询的编号,表示查询中执行select子句或操作表的顺序 |
select_type | 查询类型 |
table | 对应行的表名称 |
partitions | 匹配记录的分区 |
type | 访问类型 |
passible_keys | 查询可以用到的索引 |
keys | 实际使用的索引 |
key_len | 索引中使用的字节数,可通过该列计算查询中使用的索引的长度 |
ref | 表在key列记录的索引中查找使用的列或常量 |
rows | 估算执行查询必须检查的行数 |
filtered | 按表条件过滤的表行占表的百分比 |
Extra | 如何解析查询的其他信息 |
列详细介绍
id
执行顺序从上至下;如果是子查询,id的序号会递增,id的值越大优先级越高,越先被执行。id相同则从上往下执行,id为NULL最后执行。
select_type
显示对应行是简单查询还是复杂select(3种复杂类型)。
- SIMPLE:简单SELECT,不使用子查询和UNION
- PRIMARY:如果查询有复杂的子部分,则最外层部分标记为PRIMARY
- SUBQUERY:子查询中的SELECT,不在FROM子句中
- DERIVED:FROM子句的子查询,MySQL会递归执行将结果放到一个临时表中。服务器内部称其为派生表
- UNION:在UNION中的第二个和后面的SELECT语句
- UNION RESULT:UNION的匿名临时表检索结果
table
对应行访问的表名称,可以在这一列从上往下观察MySQL的优化器为查询选择的关联顺序。
type
这一列显示的是访问类型。MySQL决定如何查找表中的行。下面按访问方法,从最好到最差讲解。
NULL>system>const>eq_ref>ref>fulltext>ref_or_null>index_merge>unique_subquery>index_subquery>range>index>ALL //最好到最差
备注:掌握以下常见的即可
NULL>system>const>eq_ref>ref>range>index>ALL
-
NULL:MySQL能在优化阶段分解查询语句,在执行阶段甚至不用再访问表或索引。例:
-
system:表只有一行记录(=系统表)。这是const联接类型的特例。
-
const:该表最多具有一个匹配行,该行在查询开始时读取。因为只有一行,所以优化器的其余部分可以将这一行中列的值视为常量。
const在将PRIMARY KEY或 UNIQUE index与常量值进行比较时使用。const表非常快,因为它们只读取一次。例:
SELECT * FROM tb_name WHERE primary_key=1;
SELECT * FROM tb_name WHERE primary_key_part1=1 AND primary_key_part2=2;
- eq_ref:最多只返回一条符合条件的记录,常见于主键或唯一索引扫描。MySQL对于这类型访问优化做得非常好,因为无需估计匹配行的范围或找到匹配行后再继续查找。除了 system和 const类型,这是最好的联接类型。例:
SELECT * FROM ref_table,other_table WHERE ref_table.key_column=other_table.column;
-
ref:索引访问(也叫做索引查找),返回所有匹配某个单独值的行。可能会找到多个符合条件的行,因此,它是查找和扫描的混合体。
此类索引访问只有使用非唯一性索引或者唯一性索引的非唯一性前缀时才会发生。例:
SELECT * FROM ref_table WHERE key_column=expr;
SELECT * FROM ref_table,other_table WHERE ref_table.key_column=other_table.column;
- range:范围扫描,在where语句中出现between、<>、in、or等查询。例:
SELECT * FROM tb_name WHERE key_column BETWEEN 10 and 20;
SELECT * FROM tb_name WHERE key_column IN (10,20,30);
-
index:这个跟全表扫描一样,只是MySQL扫描表时按索引次序进行而不是行。主要优点是避免了排序, 缺点是要承担按索引次序读取整个表的开销。
如果在Extra列出现 Using index,说明在使用覆盖索引,只扫描索引的数据,而不是按索引次序的每行。比按索引次序全表扫描开销要少很多。 -
ALL:全表扫描
key_len
索引里使用的字节数,如果MySQL使用的是索引里的某些列,可以通过这个值计算出具体是哪些列。
key_len显示的值为索引字段的最大可能长度,并非实际使用长度。key_len是查找表的定义计算得出,而不是表中的数据
rows
估计要检查的行数
MySQL中数据的单位都是页(每页16k),MySQL又采用了采样统计的方法,采样统计的时候,InnoDB默认会选择N个数据页,统计这些页面上的不同值,得到一个平均值,然后乘以这个索引的页面数,就得到了这个索引的基数。
Extra
输出包含MySQL解决查询的额外信息,不适合在其它列中显示但十分重要
常见的重要值如下:
-
Using index:MySQL将使用覆盖索引,以避免访问表
-
Using where:存储引擎检索行后进行过滤,限制匹配下一个表或发送到客户端的行
-
Using temporary:使用了临时表保存结果,常见于order by 和 group by
-
Using filesort:MySQL会对结果使用一个外部索引排序,而不是按照表内的索引次序进行读取。当Query中包含 order by 操作,而且无法利用索引完成的排序操作称为“文件排序”
-
Range checked for each record (index map: N):MySQL找不到好用的索引,N是显示在possible_keys列中索引的位图。例如,0x19(二进制11001)的值表示考虑了索引1、4和5。
以下是一些相关限制
• EXPLAIN不会告诉你关于触发器、存储过程或用户自定义函数对查询的影响
• EXPLAIN不能显示MySQL在执行查询时所作的特定优化
参考链接:
MySQL手册