本文参考 MySQL官方文档对explain的解释
语法
explain [extended|partitions] SQL_Statement
在较早的 MySQL 版本(5.7之前)中,分区和扩展信息是使用EXPLAIN PARTITIONS
和EXPLAIN EXTENDED
生成的。仍然可以识别这些语法的向后兼容性,但是默认情况下现在启用分区和扩展输出,因此PARTITIONS
和EXTENDED
关键字是多余的并且已弃用。使用它们会导致警告,并且在将来的 MySQL
版本中会将它们从EXPLAIN
语法中删除。
您不能在同一EXPLAIN
语句中一起使用已弃用的PARTITIONS
和EXTENDED
关键字。此外,这两个关键字都不能与FORMAT选项一起使用。
EXPLAIN 输出列
EXPLAIN
的每个输出行均提供有关一个 table
的信息,列名显示在 table
的第一列中;第二列提供使用FORMAT=JSON
时在输出中显示的等效属性名称。本文后面只分析第一列的情况,更多详细信息参考mysql官方文档。
Column | JSON Name | Meaning |
---|---|---|
id | select_id | SELECT标识符 |
select_type | None | SELECT类型 |
table | table_name | 输出行 table |
partitions | partitions | 匹配的分区 |
type | access_type | 联接类型 |
possible_keys | possible_keys | 可能的索引选择 |
key | key | 实际选择的索引 |
key_len | key_length | 所选键的长度 |
ref | ref | 与索引比较的列 |
rows | rows | 估计要检查的行 |
filtered | filtered | 按 table 条件过滤的行百分比 |
Extra | None |
下面对这些字段进行详细解释
id
SELECT
识别符,这是SELECT
的查询序列号。如果该行引用其他行的并集结果,则值可以为NULL
。在这种情况下,table
列显示类似于<unionM,N>
的值,以指示该行引用具有id
值M
和 N
的行的并集。
不同级别的id
,高级别先执行
同一级别的id
从上到下
select_type
就是select类型,可以有以下几种
select_type | 含义 |
---|---|
SIMPLE | 简单SELECT ,不使用UNION 或子查询 |
PRIMARY | 子查询中最外层查询,查询中若包含任何复杂的子部分,最外层的select 被标记为PRIMARY |
UNION | UNION 中的第二个或后面的SELECT 语句 |
DEPENDENT UNION | UNION 中的第二个或后面的SELECT 语句,依赖于外面的查询 |
UNION RESULT | UNION 的结果 |
SUBQUERY | 子查询中的第一个SELECT |
DEPENDENT SUBQUERY | 子查询中的第一个SELECT ,依赖于外部查询 |
DERIVED | 派生表的SELECT (FROM 子句的子查询) |
MATERIALIZED | 物化子查询 |
UNCACHEABLE SUBQUERY | 一个子查询的结果不能被缓存,必须重新评估外链接的第一行 |
UNCACHEABLE UNION | 属于不能被缓存的UNION 中的第二个或后面的SELECT 语句 |
table
输出行所引用的 table
的名称。有时也可以是简称(查询中命名的某个表的别名或者某一步子查询结果的别名)
partitions
查询将从中匹配记录的分区。对于非分区 table,该值为NULL
。
type
联接类型(体现性能),从上到下,性能由低到高
type | 含义 |
---|---|
ALL | 全表扫描 |
index | 全索引扫描 |
range | 范围扫描 |
index_subquery | 子查询的列是普通索引 |
unique_subquery | 子查询的列是唯一索引 |
index_merge | or查询会使用到的类型 |
ref_or_null | 和ref类似,使用普通索引查询,但是要查询null值 |
fulltext | 使用全文索引进行查询 |
ref | 使用普通索引进行查询 |
eq_ref | 当连接使用索引的所有部分且索引为PRIMARY KEY 或UNIQUE NOT NULL 索引时使用 |
const | 最多只有一条返回记录,比如主键查询 |
system | 表只有一行记录(等于系统表),这是const类型的特例 |
possible_keys
表示MySQL
可以选择从中查找 table 中各行的索引。请注意,此列完全独立于EXPLAIN的输出中显示的 tableSequences
。这意味着possible_keys
中的某些键实际上可能无法用于生成的 tableSequences
。
如果此列为NULL(或在 JSON
格式的输出中未定义),则没有相关的索引。在这种情况下,您可以通过检查WHERE
子句以检查其是否引用某些适合索引的列来提高查询性能。如果是这样,请创建一个适当的索引,然后再次使用EXPLAIN
检查查询。
key
MySQL 实际决定使用的索引。
key_len
MySQL 实际决定使用的索引的长度。
ref
显示将哪些列或常量与key
列中命名的索引进行比较,以从 table 中选择行
rows
表示 MySQL 预估执行查询必须检查的行数。
filtered
表示将被 table 条件过滤的 table 行的估计百分比。
最大值为 100,表示没有行过滤发生。值从 100 减小 table 示过滤量增加。
Extra
本列包含有关 MySQL 如何解析查询的其他信息。
以下很多内容这里只是搬运,实际没见过。常见的已加粗
具体值解释
Child of 'table' pushed join@1
该 table 在可以下推到 NDB
内核的 Connecting
被称为table
的子级。启用下推联接时,仅适用于 NDB
群集。有关更多信息和示例,请参见ndb_join_pushdown
服务器系统变量的描述。
const row not found
对于诸如SELECT ... FROM tbl_name
的查询,该表为空。
Deleting all rows
(JSON 属性:message
)
对于DELETE,某些存储引擎(例如MyISAM)支持处理程序方法,该方法以一种简单而快速的方式删除所有 table 行。如果引擎使用此优化,则会显示此Extra值。
Distinct
MySQL
正在寻找不同的值,因此在找到第一个匹配的行后,它将停止为当前行组合搜索更多行。
FirstMatch(tbl_name)
半连接 FirstMatch 连接快捷方式用于 tbl_name
。
Full scan on NULL key
当优化器无法使用索引查找访问方法时,这会作为子查询优化的后备策略发生。
Impossible HAVING
HAVING
子句始终为 false,无法选择任何行。
Impossible WHERE
WHERE
子句始终为 false,无法选择任何行。
Impossible WHERE noticed after reading const tables
MySQL 已读取所有const
(和system
)table,并注意WHERE子句始终为 false。
LooseScan(m..n)
使用半连接的 LooseScan 策略。 * m
和 n
*是关键 Component 号。
No matching min/max row
没有行满足诸如SELECT MIN(...) FROM ... WHERE condition
之类的查询的条件。
no matching row in const table
对于具有联接的查询,存在一个空 table 或没有满足唯一索引条件的行的 table。
No matching rows after partition pruning
对于DELETE
或UPDATE
,优化器在分区修剪后找不到要删除或更新的内容。 SELECT
语句的含义与Impossible WHERE
相似。
No tables used
该查询没有FROM
子句,或者没有FROM DUAL
子句。
对于INSERT
或REPLACE
语句,如果没有SELECT
部分,则EXPLAIN
将显示此值。
Not exists
MySQL
能够对查询进行LEFT JOIN
优化,并且在找到与LEFT JOIN
条件匹配的一行后,不检查该 table 中的更多行以进行前一行的组合。
Plan isn't ready yet
当优化程序尚未完成为在命名 Connecting 执行的语句的执行计划的创建时,此值出现在连接说明处。如果执行计划输出包含多行,则它们中的任何一个或全部都可以具有Extra值,这取决于优化程序确定完整执行计划的进度。
Range checked for each record (index map: N)
MySQL 找不到理想的索引来使用,但是发现在知道先前表中的列值之后可能会使用某些索引。对于上表中的每个行组合,MySQL
检查是否可以使用range
或index_merge
访问方法来检索行。这不是很快,但是比根本没有索引的连接要快。
Scanned N databases
这表示在处理INFORMATION_SCHEMA
表的查询时服务器执行的目录扫描次数,
Select tables optimized away
优化器确定最多应返回一行,以及要生成该行,必须读取确定的一组行。当在优化阶段可以读取要读取的行时(例如,通过读取索引行),则在查询执行期间无需读取任何表。
Skip_open_table
,Open_frm_only
,Open_full_table
这些值 table 示适用于INFORMATION_SCHEMA
table 查询的文件打开优化
Skip_open_table
:不需要打开 table 文件。通过扫描数据库目录,该信息已在查询中可用。
Open_frm_only
:仅需要打开 table 的.frm
文件。
Open_full_table
:未优化的信息查找。必须打开.frm
,.MYD
和.MYI
文件。
Start temporary
,End temporary
这表明临时 table 用于半联接重复淘汰策略。
unique row not found
对于诸如SELECT ... FROM tbl_name
的查询,没有任何行满足 table 上UNIQUE
索引或PRIMARY KEY
的条件。
Using filesort
MySQL 必须额外进行一遍排序,以找出如何按排序Sequences检索行。排序是通过根据联接类型遍历所有行并存储与WHERE
子句匹配的所有行的排序键和指向该行的指针来完成的。然后对键进行排序,并按排序 Sequences 检索行
Using index
仅使用索引树中的信息从表中检索列信息,而不必进行其他查找以读取实际行。当查询仅使用属于单个索引的列时,可以使用此策略。
对于具有用户定义的聚集索引的InnoDB表,即使Extra列中不存在Using index,也可以使用该索引。如果type
是index
且key是PRIMARY就是这种情况。
Using index condition
通过访问索引Tuples
并首先对其进行测试以确定是否读取完整的表行来读取表。以此方式,除非必要,否则索引信息用于推迟(“下推”)读取整个表所有行。
Using index for group-by
与Using index
table 访问方法类似,Using index for group-by
table 示 MySQL 找到了一个索引,该索引可用于检索GROUP BY
或DISTINCT
查询的所有列,而无需对实际 table 进行任何额外的磁盘访问。此外,以最有效的方式使用索引,因此对于每个组,仅读取少数索引条目。
Using join buffer (Block Nested Loop)
,Using join buffer (Batched Key Access)
来自较早联接的 table 被部分读取到联接缓冲区中,然后从缓冲区中使用它们的行来执行与当前 table 的联接。 (Block Nested Loop)
table 示使用块嵌套循环算法,(Batched Key Access)
table 示使用批处理密钥访问算法。也就是说,对EXPLAIN输出的前一行中的 table 中的键进行缓冲,并从出现Using join buffer
的行所代 table 的 table 中批量提取匹配的行。
Using MRR
使用多范围读取优化策略读取 table。
Using sort_union(...)
,Using union(...)
,Using intersect(...)
这些指示了特定算法,该算法显示了如何针对index_merge
连接类型合并索引扫描。
Using temporary
为了解决该查询,MySQL
需要创建一个临时表来保存结果。如果查询包含GROUP BY
和ORDER BY
子句以不同的方式列出列,通常会发生这种情况。
Using where
WHERE
子句用于限制要与下一张表匹配或发送到客户端的行。除非您专门打算从表中获取或检查所有行,否则如果Extra
的值不是Using where
且表连接类型为ALL
或index
,则查询中可能会出错。
Using where with pushed condition
此项仅适用于NDB
表格。这意味着NDB Cluster
正在使用条件下推优化来提高在非索引列和常量之间进行直接比较的效率。在这种情况下,条件被“压入”群集的数据节点,并同时在所有数据节点上进行评估。这样就无需通过网络发送不匹配的行,并且在可以但不使用条件下推的情况下,可以将此类查询的速度提高 5 到 10 倍。
Zero limit
该查询具有LIMIT 0
子句,无法选择任何行。