Mysql EXPLAIN

558 阅读4分钟

EXPLAIN

EXPLAIN 解释了MYSQL如何处理语句:表如何关联以及以何种顺序关联。在EXPLAIN的帮助下,你可以看到应该在何处向表添加索引,还可以检查优化器是否以最佳顺序关联表。

EXPLAIN Output Format

EXPLAIN Output Columns

EXPLAIN Output Columns EXPLAIN解释计划输出结果的表头,即上图红色款内内容。

1.id

select查询语句标识。

2.select_type

查询语句类型,所有的查询见下表:

查询类型 JSON输出 说明
SIMPLE None 简单查询,没有使用关联查询或者子查询
PRIMARY None 最外层的查询,即直接查表
UNION None 关联查询
DEPENDENT UNION dependent (true) 关联子查询
UNION RESULT union_result 关联查询结果
SUBQUERY None 子查询
DEPENDENT SUBQUERY dependent (true) --
DERIVED None 衍生表
MATERIALIZED materialized_from_subquery --
UNCACHEABLE SUBQUERY cacheable (false) --
UNCACHEABLE UNION cacheable (false) --

3.table

表名称

4.type

表关联类型,详见第二小节EXPLAIN Join Types

5.possible_keys

MySQL可以选择使用的索引。

如果该列值为NULL,说明索引可用。此时,你可能需要通过检查WHERE子语句,检查是否关联了某些列或适合索引的列。如果关联了,可以创建合适的索引。

查看表使用了哪些索引,可以使用以下SQL:

SHOW INDEX FROM tbl_name

6.key

MYSQL决定使用的索引。

7.key_len

MYSQL决定使用的索引的长度,key_len的长度能够让你决定使用一组索引中的哪些索引;

8.ref

显示将哪些列或常量与key列中指定的索引进行比较,以便从表中选择行数据。

9.rows

执行查询必须的扫描行数。

10.Extra

暂不做叙述

EXPLAIN Join Types

type 描述了表之间是如何关联的。关联性从最好到最差的:

1.system

该表只有一行数据,这是const关联的特殊情况。

2.const

该表最多有一条匹配的数据,并且在查询时开始读取。因为只有一行,所以这一行中的列的值可以被优化器的其余部分视为常量。const表非常快,因为它们只读取一次。

将主键或惟一索引的所有部分与常量值进行比较时,const被使用。例:

SELECT * FROM tbl_name WHERE primary_key=1;

SELECT * FROM tbl_name
  WHERE primary_key_part1=1 AND primary_key_part2=2;

3.eq_ref

从关联查询的多个表中读取一条数据,除了system、const关联类型之外,eq_ref是最好的关联类型。索引的所有组成部分被用作关联查询的条件,并且索引是主键或唯一非空索引时,关联类型就是req_ref

eq_ref可用于使用=操作符比较的索引列。比较值可以是常量,也可以是两个表关联字段的表达式。如:

#表达式
SELECT * FROM ref_table,other_table
  WHERE ref_table.key_column=other_table.column;

#表达式和常量
SELECT * FROM ref_table,other_table
  WHERE ref_table.key_column_part1=other_table.column
  AND ref_table.key_column_part2=1;

4.ref

从多表关联查询的结果中读取所有的匹配数据。ref所代表的是无法精确匹配一行数据,只能匹配多条数据。

ref被使用的情况:

  • 如果是联合索引,则使用了索引的最左前缀
  • 使用的键不是主键或唯一索引;
#非主键或非唯一索引
SELECT * FROM ref_table WHERE key_column=expr;

#非主键或非唯一索引
SELECT * FROM ref_table,other_table
  WHERE ref_table.key_column=other_table.column;

#非主键或非唯一索引
SELECT * FROM ref_table,other_table
  WHERE ref_table.key_column_part1=other_table.column
  AND ref_table.key_column_part2=1;

5.fulltext

表示使用了全文索引。FULLTEXT索引只能用于INNODB及MySAM表,可应用于CHAR、VARCHAR、TEXT字段。

MySQL中like '%text%'是无法使用索引的,唯一可能使用的索引是'text%,'所以实际使用中尽量避免使用like。

6.ref_or_null

ref_or_null关联类型与ref类似,但是MySQL会额外搜索包含NULL值的数据。ref_or_null最常用于解决子查询,如:

SELECT * FROM ref_table
  WHERE key_column=expr OR key_column IS NULL;

7.index_merge

index_merge表明使用了联合索引。在这种情况下,key列中包含了所有使用的索引,key_len包含了所有使用的索引的最长的部分。

8.unique_subquery

unique_subquery直译'唯一子查询'。它可以通过使用IN查询来代替eq_ref,即主键或唯一索引的范围查询,如:

#IN
SELECT * FROM ref_table
  WHERE primary_key IN (SELECT primary_key FROM single_table WHERE some_expr)

unique_subquery只是一个索引查找函数,它可以完全替换子查询以提高查询效率。

9.index_subquery

index_subquery直译‘索引子查询’。index_subqueryunique_subquery类似,但是index_subquery可以适用于非唯一索引。如:

SELECT * FROM ref_table
  WHERE key_column IN (SELECT key_column FROM single_table WHERE some_expr)

10.range

只检索给定范围内的数据,使用一个索引查询匹配的结果数据。key列展示了被使用的索引(一个),key_len展示了被使用的索引的最长的部分,ref为null。

当使用=、<>、>、>=、<、<=、is NULL、<=>、BETWEEN、LIKE或IN()中任意一个运算符时,可以使用range。如:

SELECT * FROM tbl_name
  WHERE key_column = 10;

SELECT * FROM tbl_name
  WHERE key_column BETWEEN 10 and 20;

SELECT * FROM tbl_name
  WHERE key_column IN (10,20,30);

SELECT * FROM tbl_name
  WHERE key_part1 = 10 AND key_part2 IN (10,20,30);

11.index

除了索引树被扫描之外,indexall 是一样的。

  • 如果索引覆盖索引,查询的列可以从索引中得到,那么只扫描索引树。在这种情况下,Extra列会输出Using index。仅扫描索引通常比全表扫描都快,因为索引通常小于表数据。
  • 使用索引并按索引顺序去去检索数据,会执行全表扫描。在这种情况下,Extra列不会会输出Using index

12.all

关联查询的所有表的所有数据进行扫描,可以通过添加索引来避免全表扫描。