介绍
查看优化器如何决定执行查询的主要方法。可以深入了解 MySQL 的基于开销的优化器,还可以获得很多可能被优化器考虑的访问策略细节,以及当运行 SQL 语句时哪种策略预计会被优化器采用。
MySQL 执行计划调用方式
EXPLAIN SELECT
变体
EXPLAIN EXTENDED SELECT
将执行计划反编译成 SELECT 语句,运行 SHOW WARNINGS
可得到被 MySQL 优化器优化后的查询语句
EXPLAIN PARTITIONS SELECT
用于分区表的 EXPLAIN 生成 QEP 信息
执行计划包含的信息
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
|---|
id
包含一组数字,表示查询中执行 SELECT 子句或操作表的顺序。
- id 相同,执行顺序由上至下
- 如果是子查询,id 的序号会递增,id 值越大优先级越高,越先被执行
- id 如果相同可以认为是一组,从上往下顺序执行,在所有组中,id 值越大,优先级越高,越先执行。
select_type
是指查询中每个 select 子句的类型(简单 or 复杂)
- SIMPLE:查询中不包含子查询或 UNION
- PRIMARY:查询中最外层的的 SELECT (如两表做UNION或者存在子查询的外层的表操作为 PRIMARY,内层的操作为 UNION)
- UNION: UNION 操作中,查询中处于内层的 SELECT (内层的 SELECT 语句与外层的 SELECT 语句没有依赖关系)
- DEPENDENT UNION: UNION 操作中,查询中处于内层的 SELECT (内层的 SELECT 语句与外层的 SELECT 语句有依赖关系)
- UNION RESULT: UNION 操作的结果,id值通常为null
- SUBQUERY: 子查询中首个 SELECT(如果有多个子查询存在)
- DEPENDENT SUBQUERY: 子查询中首个 SELECT,但依赖于外层的表(如果有多个子查询存在)
- DERIVED: 被驱动的 SELECT 子查询(子查询位于 FROM 子句)
- MATERIALIZED: 被物化的子查询
- UNCACHEABLE SUBQUERY: 对于外层的主表,子查询不可被物化,每次都需要计算(耗时操作)
- UNCACHEABLE UNION: UNION 操作中,内存的不可被物化的子查询(类似于 UNCACHEABLE SUBQUERY)
type
表示 MySQL 在表中找到所需行的方式,又称‘访问类型’,常见的访问类型如下:
ALL, index, range, ref, eq_ref, const, system, NULL。从左到右,性能从最差到最好。
- ALL: Full Table Scan, MySQL 将遍历全表以找到匹配的行
- index: Full Index Scan, index 与 ALL 的区别为 index 类型只遍历索引树
- range: 索引范围扫描,对索引的扫描开始于某一点,返回匹配值域的行。显而易见的索引范围扫描是带有 between 或者 where 子句里带有<,>查询。当 MySQL 使用索引去查找一系列值时,例如 in 和 or 列表,也会显示 range(范围扫描),当然性能上是有差异的。
- ref: 使用非唯一索引扫描或者唯一索引的前缀扫描,返回匹配某个单独值的记录行。
- eq_ref: 类似 ref,区别就在使用的索引是唯一索引,对于每个索引键值,表中只有一条记录匹配,简单来说,就是多表连接使用 primary key 或者 unique key 作为关联条件。
- const,system: 当 MySQL 对查询某部分进行优化,并转换为一个常量时,使用这些类型访问。如将主键置于 where 列表中, MySQL 就能将该查询转换为一个常量。
- system: 是 const 类型的特例,当查询的表只有一行的情况下,使用 system
- NULL: MySQL 在优化过程中分解语句,执行是甚至不用访问表或索引,例如从一个索引列里选取最小值可以通过单独索引查找完成。
possible_keys
指出 MySQL 能使用哪个索引在表里找到记录,查询设计到的字段上若存在该索引,则索引将被列出,但不一定被查询使用。
key
显示 MySQL 在查询中实际使用的索引,若没有使用索引,显示为 NULL。
key_len
表示索引中使用的字节数,可以通过该列计算查询中使用的索引的长度(key_len 显示的值为索引字段的最大可能长度,并非实际使用长度,即 key_len 是根据表定义计算而得,不是通过表内检索出的)
ref
表示上述表的连接匹配条件,即哪些列或常量被用于查找索引列上的值。
rows
表示 MySQL 根据表统计信息及索引选用情况,估算的找到所需要读取的行数。
Extra
包含不适合在其他列中显示但十分重要的额外信息。
- Using index: 该值表示相应的 SELECT 操作中使用了覆盖索引(Covering Index)
覆盖索引(Covering Index): MySQL 中可以利用索引返回 SELECT 列表中的字段,而不必根据索引再次读取数据文件。包含所有满足查询需要的数据的索引称为覆盖索引(Covering Index)。注意:如果要使用覆盖索引,一定要注意 SELECT 列表中只取出需要的列,不可 SELECT * ,因为如果将所有字段一起做索引会导致索引文件过大,查询性能下降。
- Using where: 表示 MySQL 服务器将在存储引擎检索后再进行过滤。许多 where 条件里涉及索引中的列,当(并且如果)它读取索引时,就能被存储引擎检验,因此不是所有带 where 字句的查询都会显示 ‘Using where’。有时‘Using where’的出现就是一个暗示:查询可受益与不同的索引。
- Using temporary: 表示 MySQL 需要使用临时表来存储结果集,常见于排序和分组查询。这个值表示使用了内部临时(基于内存的)表。一个查询可能用到多个临时表。有很多原因都会导致 MySQL 在执行查询期间创建临时表。两个常见的原因是在来自不同表上使用了 DISTINCT ,或者使用了不同的 ORDER BY 和 GROUP BY列。可以强制指定一个临时表使用基于磁盘的 MyISAM 存储引擎,这样做的原因主要有两个:
- 内部临时表占用的空间超过min(tmp_table_size, max_heap_table_size)系统变量的限制。
- 使用了 TEXT/BLOB 列
- Using filesort: MySQL 中无法利用索引完成的排序操作称为‘文件排序’
- Using join buffer: 该值强调了在获取连接条件时没有使用索引,并且需要连接缓存区来存储中间结果。如果出现了这个值,那应该注意,根据查询的具体情况可能需要添加索引来改进性能。
- Impossible where: 这个值强调了 where 语句会导致没有符合条件的行。
- Select tables optimized away: 这个值意味着仅通过使用索引,优化器可能仅从聚合函数结果中返回一行。
- Index merges: 当 MySQL 决定要在一个给定的表上使用超过一个索引的时候,就会出现以下格式中的一个,详细说明使用的索引以及合并的类型。
- Using sort_union(...)
- Using union(...)
- Using intersect(...)
总结
- EXPLAIN不会告诉你关于触发器,存储过程的信息或用户自定义函数对查询的影响情况
- EXPLAIN不考虑各种Cache
- EXPLAIN不能显示MySQL在执行查询时所做的优化工作
- 部分统计信息是估算的,不是准确值
- EXPLAIN只能解释SELECT操作,其它操作要重写为SELECT后查看执行计划