文章目录
是什么
MySQL的Explain命令可以用于分析和优化SQL语句的性能。该命令可以模拟查询的执行计划,并提供有关如何执行查询的详细信息。
通过查看Explain输出,您可以确定是否使用了正确的索引,以及是否存在任何潜在的性能瓶颈。您可以使用这些信息来调整查询以提高其性能,例如添加索引或重写查询以使用更有效的操作顺序。
使用
在你书写的SQL语句加一个单词 - explain,然后将 explain + SQL执行后会出现一个表,这个表会告诉你MySQL优化器是怎样执行你的SQL的。下面我们来讲解一下表格里面的字段。
本文以示例为基础来讲解各个字段,示例表:
表1
CREATE TABLE `background_log` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`task` varchar(255) NOT NULL DEFAULT '',
PRIMARY KEY (`id`),
KEY `task_index` (`task`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
表2
CREATE TABLE `application` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`team_id` int(11) NOT NULL DEFAULT '0' COMMENT '组织id',
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
示例1
EXPLAIN SELECT * FROM `application` WHERE `team_id` = (SELECT `team_id` FROM `application` WHERE `id`= 202)
示例2
EXPLAIN SELECT id FROM (SELECT `id`, `team_id` FROM `application` WHERE `team_id` = 13) a;
示例3
EXPLAIN SELECT id FROM application;
示例4
EXPLAIN SELECT * FROM `background_log` WHERE `task`='拉取源代码完成.';
字段详解
id
查询中每个操作的唯一标识符,表示执行的顺序
- id值越大,优先级越高,越先执行
- id如果相同,可以认为是一组,从上往下顺序执行
如实例1所示
id为2的子查询更先执行,然后再执行id为1的主查询。
select_type
这一列返回查询类型,是简单查询还是复杂查询。简单查询为SIMPLE;复杂查询包括UNION,普通子查询和FROM子查询。具体的枚举类型包括:
- SIMPLE: 简单SELECT,不使用UNION或子查询等
- PRIMARY: 查询中若包含任何复杂的子部分,最外层的select被标记为PRIMARY
- UNION: UNION中的第二个或后面的SELECT语句
- DEPENDENT UNION: UNION中的第二个或后面的SELECT语句,取决于外面的查询
- UNION RESULT: UNION的结果
- SUBQUERY: 子查询中的第一个SELECT
- DEPENDENT SUBQUERY: 子查询中的第一个SELECT,取决于外面的查询
- DERIVED: 派生表的SELECT, FROM子句的子查询
- UNCACHEABLE SUBQUERY: 一个子查询的结果不能被缓存,必须重新评估外链接的第一行
如实例1所示
这个查询是普通子查询,第一行是主要查询,第二行是子查询。
普通子查询和FROM子查询的区别
普通子查询
普通子查询是嵌套在另一个查询的SELECT语句中,用于返回一个单一的值或多个值,通常与WHERE子句一起使用。例如:
SELECT column_name
FROM table_name
WHERE column_name = (SELECT column_name FROM another_table WHERE condition);
FROM子查询
FROM子查询是嵌套在另一个查询的FROM子句中,用于返回一个虚拟表,通常与JOIN子句一起使用。例如:
SELECT column_name
FROM table_name
JOIN (SELECT column_name FROM another_table WHERE condition) AS sub_table
ON table_name.column_name = sub_table.column_name;
在上述示例中,子查询(SELECT column_name FROM another_table WHERE condition)返回一个虚拟表,并将其用于JOIN子句中与table_name表进行连接。
table
显示这一行的数据是关于哪张表的,derivedx表示临时内存表。
如实例2所示
实例展示的是一个FROM子查询,FROM子查询的 derivedx 表示临时内存表。
partitions
该列显示的为分区表命中的分区情况。非分区表该字段为空(null)。
type
type字段表示MySQL在执行查询时使用的访问方法,也就是在查找匹配行时使用的算法。type字段是MySQL查询优化器选择索引的重要指标之一,它的值越优越快速,查询性能越好。以下性能由快到慢:
system
这是最高级别的查询类型,表示只有一行数据,因为这个查询只是对系统表中的一行数据进行操作,不需要扫描表。
const
表示使用主键或唯一索引进行匹配,查询结果只有一行数据。这是最快的查询类型之一。
eq_ref
表示连接时使用了唯一索引,常见于连接查询(Join),并且在查询结果集中使用索引的所有列的值都相等。
ref
使用非唯一索引或者唯一索引的非唯一性前缀
如实例4所示
查询使用普通索引,所以type 为 ref
range
表示使用索引扫描,只返回索引中匹配指定范围的行数据。这个范围可能是一个单独的值,或是一个范围。
一般使用了这些比较符:
- =
- <>
- >
- >=
- <
- <=
- IS NULL
- <=>
- BETWEEN
- IN()
index
表示进行全索引扫描,这种情况下MySQL将扫描整个索引来查找匹配的行,而不是扫描整个表。
如实例3所示
虽然查询使用了id这个索引,但是因为要对整个表查询,索引使用的是 index
all
表示进行全表扫描,这意味着MySQL将扫描整个表以查找匹配的行。这是最慢的查询类型。
possible_keys
显示了查询可以使用哪些索引,这是基于查询访问的列和使用的比较操作符来判断的
key
这一列显示了MySQL决定采用哪个索引来优化对该表的访问,如果索引没有出现在possible_keys列中,那么MySQL选用他是出于另外的原因。
key和possible_keys的区别
possible_keys揭示了哪一个索引能有助于高效进行查询,而key显示的是优化采用哪一个索引可以最小化查询成本。
key_len
key_len 字段表示 MySQL 在使用索引时,使用的索引长度(字节数),下面是详细解释:
- 如果索引是一个主键、唯一或普通索引,则 key_len 就是该索引的长度。
- 如果索引是一个联合索引(即包含多个字段的索引),则 key_len 表示索引中所有字段的长度之和。
- 如果索引只是一个前缀索引,则 key_len 表示前缀的长度,而不是整个字段的长度。
- 如果没有使用索引,则 key_len 为 NULL。
ref
用于表示当前查询所使用的索引列,以及使用了哪些表和哪些列进行了关联。
一般有以下两种情况:
- 如果是 a=1 这种情况,则为const
- 如果是表join的情况 a.t1=b.t1, 则列出具体的列。多个列以逗号隔开。
rows
这一列是MySQL估计为了找到所需要的行而要读取的行数。(不是实际读出来一定需要的行数,而是根据抽样法预估出来的行数)
filtered
Filter是查询的行数与总行数的比值。其实作用与rows差不多,都是数值越小,效率越高。
Extra
Using index
使用覆盖索引,防止回表
Using index condition
在MySQL 5.6版本后加入的新特性(Index Condition Pushdown);会先条件过滤索引,过滤完索引后找到所有符合索引条件的数据行,随后用 WHERE 子句中的其他条件去过滤这些数据行;
Using where
存储引擎检索后再进行过滤
Using temporary
结果排序时会使用一个临时表