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_subquery与unique_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
除了索引树被扫描之外,index 与 all 是一样的。
- 如果索引覆盖索引,查询的列可以从索引中得到,那么只扫描索引树。在这种情况下,
Extra列会输出Using index。仅扫描索引通常比全表扫描都快,因为索引通常小于表数据。 - 使用索引并按索引顺序去去检索数据,会执行全表扫描。在这种情况下,
Extra列不会会输出Using index。
12.all
关联查询的所有表的所有数据进行扫描,可以通过添加索引来避免全表扫描。