MySQL 执行计划 (二)
注:本文的所有例子都是基于MySQL 5.7
一、id:执行计划的标识符
select 查询的序列号,标识执行的顺序
如果该行引用其他行的并集结果,则值可以为NULL
。在这种情况下,table
列显示类似于
的值,以指示该行引用具有id
值* M
和 N
*的行的并集。(可以 看3.2的截图)
- id 相同,执行顺序由上至下
- id 不同,如果是子查询,id 的序号会递增,id 值越大优先级越高,越先被执行
举个例子:
如下是有子查询的一个SQL ,从执行计划上可以看到 分成了2组,
按照从id不同时,id 越大优先级越高,; id 相同,从上到下 的 原则,
可以看到先执行的是查询departments 这个表,,然后 是dept_emp表,最后才是employees 表。
和我们从语义上 里一样。先从demparts表 筛选出dept_name 是sales 和finance 的dept_no。再用查出来的dept_no 到dept_emp 表里查询 对应的emp_no。 最后才是用emp_no 查询employees表,获取最终的结果。
二、 select_type:查询类型
查询的类型,主要是用于区分普通查询、联合查询、子查询等。一般有如下几种
- SIMPLE:简单的 select 查询,查询中不包含子查询或者 union
- PRIMARY:查询中包含子部分,最外层查询则被标记为 primary
- UNION:表示 union 中的第二个或后面的 select 语句
- DEPENDENT UNION:union 中的第二个或后面的 select 语句,依赖于外面的查询
- UNION RESULT:union 的结果
- SUBQUERY:子查询中的第一个 select
- DEPENDENT SUBQUERY:子查询中的第一个 select,依赖于外面的查询
- DERIVED:派生表的 select(from 子句的子查询)
- MATERIALIZED:物化子查询
- 产生中间临时表(实体)
- 临时表自动创建索引并和其他表进行关联,提高性能
- 和子查询的区别是,优化器将可以进行 MATERIALIZED 的语句自动改写成 join,并自动创建索引
- UNCACHEABLE SUBQUERY:不会被缓存的并且对于外部查询的每行都要重新计算的子查询
- UNCACHEABLE UNION:属于不能被缓存的 union 中的第二个或后面的 select 语句
2.1、SIMPLE
简单的 select 查询,查询中不包含子查询或者 union
2.2、PRIMARY
查询中包含子部分,最外层查询则被标记为 primary
三、table: 输出结果集的表
3.1、通常就是用户操作的用户表,这里有可能不是真实的表名,可能是你SQL的简称
3.2、
3.3、
通俗点就是: 包含在FROM子句中的子查询被标识为DERIVED,MYSQL会递归执行这类查询并放入临时表中。MYSLQ内部通过“derived table”引用这张临时表,因为这张临时表派生自子查询。
N代表子查询的id,总是执行EXPLAIN输出中后面的某一行
3.4、
四、type
访问类型,SQL 查询优化中一个很重要的指标,常见的有:system 、const 、 eq_ref 、ref 、range 、index、AL
结果值从好到坏依次是:system > const > eq_ref > ref > range > index > ALL。
4.1、system
系统表,少量数据,往往不需要进行磁盘IO
system是const类型的特例,当查询的表只有一行的情况下,使用system
4.2、const
该表最多只有一个匹配行,在查询开头读取。因为只有一行,所以优化器的其余部分可以将此行中列的值视为常量。 const表非常快,因为它们只读一次
const、system: 当MySQL对查询某部分进行优化,并转换为一个常量时,使用这些类型访问。如将主键或者唯一索引 置于where列表中,MySQL就能将该查询转换为一个常量
4.3、eq_ref
当连接使用索引的所有部分且索引是 索引PRIMARY KEY或UNIQUE NOT NULL索引时使用它。
4.4、ref
表示上述表的连接匹配条件,即哪些列或常量被用于查找索引列上的值
ref 扫描,可能出现在 join 里,也可能出现在单表普通索引里,每一次匹配可能有多行数据返回,虽然它比 eq_ref 要慢,但它仍然是一个很快的 join 类型 出现在单表普通索引里出现在多表连接查询里
4.5、range
仅检索给定范围内的行,使用索引选择行。的key 输出行中的列指示使用哪个索引。将key_len包含已使用的时间最长的关键部分。该ref列 NULL适用于此类型。
range当一个键柱使用任何的相比于恒定可使用 =, <>, >, >=, <, <=, IS NULL, <=>, BETWEEN, LIKE,或 IN()
-
4.6、index
-
该index联接类型是一样的 ALL,只是索引树被扫描。这种情况有两种:
- 如果索引是查询的覆盖索引,并且可用于满足表中所需的所有数据,则仅扫描索引树。在这种情况下,Extra专栏说 Using index。仅索引扫描通常比ALL索引的大小通常小于表数据更快 。
-
- 使用索引中的读取执行全表扫描,以按索引顺序查找数据行。 Uses index没有出现在 Extra列中。当查询仅使用属于单个索引的列时,MySQL可以使用此连接类型。
4.7、ALL
对前面表格中的每个行组合进行全表扫描。如果表是第一个未标记的表 const,通常不好,并且在所有其他情况下通常 非常糟糕。通常,您可以ALL通过添加基于常量值或早期表中的列值从表中启用行检索的索引来避免
五、partitions
记录将与查询匹配的分区。仅在使用PARTITIONS关键字时才显示此列 。非分区表显示null
六、possible_keys
该possible_keys列指示MySQL可以选择在此表中查找行的索引,指出MySQL能使用哪个索引在表中找到记录,查询涉及到的字段上若存在索引,则该索引将被列出,但不一定被查询使用
该列完全独立于EXPLAIN输出所示的表的次序。这意味着在possible_keys中的某些键实际上不能按生成的表次序使用。
如果该列是NULL,则没有相关的索引。在这种情况下,可以通过检查WHERE子句看是否它引用某些列或适合索引的列来提高你的查询性能。如果是这样,创造一个适当的索引并且再次用EXPLAIN检查查询
七、Key
key列显示MySQL实际决定使用的键(索引)
如果没有选择索引,键是NULL。要想强制MySQL使用或忽视possible_keys列中的索引,在查询中使用FORCE INDEX、USE INDEX或者IGNORE INDEX。
八、key_len
表示索引中使用的字节数,可通过该列计算查询中使用的索引的长度(key_len显示的值为索引字段的最大可能长度,并非实际使用长度,即key_len是根据表定义计算而得,不是通过表内检索出的)
不损失精确性的情况下,长度越短越好
九、ref
表示上述表的连接匹配条件,即哪些列或常量被用于查找索引列上的值
十、rows
表示MySQL根据表统计信息及索引选用情况,估算的找到所需的记录所需要读取的行数
十一、Extra
该列包含MySQL解决查询的详细信息,有以下几种情况:
11.1、Using where
表示 SQL 操作使用了 where 过滤条件不用读取表中所有信息,仅通过索引就可以获取所需数据,这发生在对表的全部的请求列都是同一个索引的部分的时候,表示mysql服务器将在存储引擎检索行后再进行过滤
11.2、Using temporary
表示MySQL需要使用临时表来存储结果集,常见于排序和分组查询,常见 group by ; order by
Extra 为 Using temporary 说明,需要建立临时表(temporary table)来暂存中间结果。
这类 SQL 语句性能较低,往往也需要进行优化。
典型的 group by 和 order by 同时存在,且作用于不同的字段时,就会建立临时表,以便计算出最终的结果集。
临时表存在两种引擎,一种是 Memory 引擎,一种是 MyISAM 引擎,如果返回的数据在 16M 以内(默认),且没有大字段的情况下,使用 Memory 引擎,否则使用 MyISAM 引擎。
11.3、Using index
SQL 所需要返回的所有列数据均在一棵索引树上,而无需访问实际的行记录。
11.4、Using index condition
Extra 为 Using index condition 说明,确实命中了索引,但不是所有的列数据都在索引树上,还需要访问实际的行记录 可以对比下上面using index语句的区别,就是多了一列description11.5、Using filesort
当Query中包含 order by 操作,而且无法利用索引完成的排序操作称为“文件排序”
11.6、Using join buffer
该值强调了在获取连接条件时没有使用索引,并且需要连接缓冲区来存储中间结果。如果出现了这个值,那应该注意,根据查询的具体情况可能需要添加索引来改进能。
Extra 为 Using join buffer (Block Nested Loop) 说明,需要进行嵌套循环计算。内层和外层的 type 均为 ALL,rows 均为4,需要循环进行4*4次计算。 这类 SQL 语句性能往往也较低,需要进行优化。 典型的两个关联表 join,关联字段均未建立索引,就会出现这种情况。常见的优化方案是,在关联字段上添加索引,避免每次嵌套循环计算 比如:如下这个例子里, test_1 表的id 列是varchar 类型,test_2 表的id列是int类型,他们虽然各自是主键索引,但是因为类型不匹配导致索引失效。11.7、Impossible where
这个值强调了where语句会导致没有符合条件的行(通过收集统计信息不可能存在结果)。
11.8、no matching row in const table
空表时查询
11.9、Select tables optimized away
这个值意味着仅通过使用索引,优化器可能仅从聚合函数结果中返回一行
比如下面的语句查询 film_id 的最大值,因为 film_id 是主键索引,根据 B+Tree 的结构,天然就是有序存放的,所以不需要等到执行阶段再进行计算,查询执行计划生成的阶段即可完成优化
11.10、No tables used
Query语句中使用from dual 或不含任何from子句