【mysql】- Expalin篇
简介
- id:在一个大的查询语句中每个 SELECT 关键字都对应一个唯一的id
- 与查询优化器有关,假如被优化过,那么可能是上下两个的id都是一样的
- select_type:SELECT 关键字对应的那个查询的类型
- SIMPLE:SELECT (not using UNION or subqueries),语句中不包含UNION或者子查询的查询都算作是 SIMPLE 类型
- 简单查询: SELECT * FROM s1
- 连接查询也算是 SIMPLE 类型:SELECT * FROM s1 INNER JOIN s2
- PRIMARY:Outermost SELECT,对于包含 UNION 、 UNION ALL或者子查询的大查询来说,它是由几个小查询组成的,其中最左边的那个查询的 select_type 值就是 PRIMARY
- 比如 SELECT * FROM s1 UNION SELECT * FROM s2
- UNION:Second or later SELECT statement in a UNION,对于包含UNION或者UNION ALL 的大查询来说,它是由几个小查询组成的,其中除了最左边的那个小查询以外,其余的小查询的 select_type 值就是 UNION
- UNION RESULT:Result of a UNION,MySQL选择使用临时表来完成UNION查询的去重工作,针对该临时表的查询的select_type 就是 UNION RESULT
- SUBQUERY:First SELECT in subquery,如果包含子查询的查询语句不能够转为对应的semi-join的形式,并且该子查询是不相关子查询,并且查询优化器决定采用将该子查询物化的方案来执行该子查询时,该子查询的第一个 SELECT 关键字代表的那个查询的 select_type 就是 SUBQUERY
- 比如:SELECT * FROM s1 WHERE key1 IN (SELECT key1 FROM s2) OR key3 = ‘a’
- select_type为SUBQUERY的子查询由于会被物化,所以只需要执行一遍
- DEPENDENT SUBQUERY:First SELECT in subquery, dependent on outer query,如果包含子查询的查询语句不能够转为对应的semi-join的形式,并且该子查询是相关子查询,则该子查询的第一个SELECT关键字代表的那个查询的select_type就是DEPENDENT SUBQUERY
- SELECT * FROM s1 WHERE key1 IN (SELECT key1 FROM s2 WHERE s1.key2 = s2.key2) OR key3 = ‘a’
- 注:select_type为DEPENDENT SUBQUERY的查询可能会被执行多次
- DEPENDENT UNION:Second or later SELECT statement in a UNION, dependent on outer query,在包含 UNION 或者UNION ALL的大查询中,如果各个小查询都依赖于外层查询的话,那除了最左边的那个小查询之外,其余的子查询的 select_type 的值就是 DEPENDENT UNION
- SELECT * FROM s1 WHERE key1 IN (SELECT key1 FROM s2 WHERE key1 = ‘a’ UNION SELECT key1 FROM s1 WHERE key1 = ‘b’)
- DERIVED:Derived table,对于采用物化的方式执行的包含派生表的查询,该派生表对应的子查询的select_type就是DERIVED
- MATERIALIZED:Materialized subquery,当查询优化器在执行包含子查询的语句时,选择将子查询物化之后与外层查询进行连接查询时,该子查询对应的select_type 属性就是 MATERIALIZED
- 如:SELECT * FROM s1 WHERE key1 IN (SELECT key1 FROM s2)
- UNCACHEABLE SUBQUERY:A subquery for which the result cannot be cached and must be re-evaluated for each row of the outer query,一个子查询的结果不能被缓存,必须重新评估外链接的第一行
- UNCACHEABLE UNION:The second or later select in a UNION that belongs to an uncacheable subquery (see UNCACHEABLE SUBQUERY)
- SIMPLE:SELECT (not using UNION or subqueries),语句中不包含UNION或者子查询的查询都算作是 SIMPLE 类型
- table:表名
- partitions:匹配的分区信息
- 当对表进行分区处理时,对于某些查询会使用到分区的情况,此时会出现涉及的分区
- type:针对单表的访问方法
- system
- 当表中只有一条记录并且该表使用的存储引擎的统计数据是精确的,比如MyISAM、Memory,那么对该表的访问方法就是 system
- const
- 根据主键或者唯一二级索引列与常数进行等值匹配时,对单表的访问方法就是const
- eq_ref
- 在连接查询时,如果
被驱动表
是通过主键
或者唯一二级索引
列等值
匹配的方式进行访问的(如果该主键或者唯一二级索引是联合索引的话,所有的索引列都必须进行等值比较),则对该被驱动表
的访问方法就是eq_ref
- 在连接查询时,如果
- ref
- 当通过
普通的二级索引列
与常量进行等值匹配时来查询某个表,那么对该表的访问方法就可能是 ref
- 当通过
- fulltext
- 全文索引,在标准的MySQL中, 只有MyISAM引擎支持全文索引。 不过在还没有正式发布的MySQL5.6中,InnoDB已经实验性质地支持全文索引了
- ref_or_null
- 当对普通二级索引进行等值匹配查询,该索引列的值也可以是NULL值时,那么对该表的访问方法就可能是 ref_or_null
- index_merge
- 索引合并,在某些场景下可以使用Intersection、Union、Sort-Union这三种索引合并的方式来执行查询
- unique_subquery
- 类似于两表连接中
被驱动表
的eq_ref访问方法,unique_subquery是针对在某些包含IN子查询
的查询语句中,如果查询优化器决定将IN子查询转换为EXISTS子查询
,并且子查询可以使用到主键
进行等值匹配的话,那么该子查询执行计划的 type 列的值就是 unique_subquery
- 类似于两表连接中
- index_subquery
- index_subquery 与 unique_subquery 类似,只不过访问子查询中的表时使用的是
普通的索引
- index_subquery 与 unique_subquery 类似,只不过访问子查询中的表时使用的是
- range
- 如果使用索引获取某些
范围区间
的记录,那么就可能使用到range访问方法
- 如果使用索引获取某些
- index
- 当我们可以使用
索引覆盖
,但需要扫描全部的索引记录
时,该表的访问方法就是index
- 当我们可以使用
- ALL
- 全表扫描
- system
- possible_keys:可能用到的索引
- key:实际上使用的索引
- key_len:实际使用到的索引长度
- 对于使用固定长度类型的索引列来说,它实际占用的存储空间的最大长度就是该固定值,对于指定字符集的变长类型的索引列来说
- 如果该索引列可以存储 NULL 值,则 key_len 比不可以存储 NULL 值时多1个字节
- 对于变长字段来说,都会有2个字节的空间来存储该变长列的实际长度
- ref:当使用索引列等值查询时,与索引列进行等值匹配的对象信息
- 在访问方法是 const 、eq_ref、ref、ref_or_null、unique_subquery、index_subquery其中之一时,ref列展示的就是与索引列作等值匹配的东西,可能是一个常量或者一个函数等
- rows:预估的需要读取的记录条数
- 如果查询优化器决定使用全表扫描的方式对某个表执行查询时,执行计划的rows列就代表预计需要扫描的行数
- 如果使用索引来执行查询时,执行计划的rows列就代表预计扫描的rows索引记录行数
- filtered:某个表经过搜索条件过滤后剩余记录条数的百分比
-
如果使用的是全表扫描的方式执行的单表查询,那么计算驱动表扇出时需要估计出满足搜索条件的记录到底有多少条
-
如果使用的是索引执行的单表扫描,那么计算驱动表扇出的时候需要估计出满足除使用到对应索引的搜索条件外的其他搜索条件的记录有多少条
-
- Extra:一些额外的信息
- No tables used:当查询语句的没有FROM语句时将会提示该额外信息
- Impossible WHERE:查询语句的 WHERE 语句永远为 FALSE 时将会提示该额外信息
- No matching min/max row:查询列表处有MIN或者MAX聚集函数,但是并没有符合WHERE语句中的搜索条件的记录时,将会提示该额外信息
- Using index:查询列表以及搜索条件中只包含属于某个索引的列,也就是在可以使用索引覆盖的情况下,在 Extra 列将会提示该额外信息
- Using index condition:有些搜索条件中虽然出现了索引列,但却不能使用到索引(索引条件下推:减去好多回表操作的成本(Extra也一样会显示Using index condition))
- Using where
- 当我们使用全表扫描来执行对某个表的查询,并且该语句的WHERE语句中有针对该表的搜索条件时,在 Extra 列中会提示上述额外信息
- 当使用索引访问来执行对某个表的查询,并且该语句的WHERE语句中有除了该索引包含的列之外的其他搜索条件时,在 Extra 列中也会提示上述额外信息
- Using join buffer (Block Nested Loop)
- 在连接查询执行过程中,当
被驱动表
不能有效的利用索引加快访问速度,MySQL一般会为其分配一块名叫 join buffer 的内存块来加快查询速度,也就是我们所讲的基于块的嵌套循环算法
- 在连接查询执行过程中,当
- Not exists:当我们使用
左/右(外)连接
时,如果WHERE语句中包含要求被驱动表的某个列等于NULL值的搜索条件,并且那个列又是不允许存储 NULL 值的,那么在该表的执行计划的 Extra 列就会提示 Not exists 额外信息 - Using intersect(…):准备使用Intersect索引合并的方式执行查询,括号中的…表示需要进行索引合并的索引名称
- Using union(…):准备使用Union索引合并的方式执行查询
- Using sort_union(…):说明准备使用Sort-Union索引合并的方式执行查询
- Zero limit:LIMIT语句的参数为 0 时,表示压根儿不打算从表中读出任何记录,将会提示该额外信息
- Using filesort:有些排序操作无法使用到索引,只能在内存中(记录较少的时候)或者磁盘中(记录较多的时候)进行排序,就会在执行计划的 Extra 列中显示 Using filesort提示;(需要使用filesort的记录很多时,过程是很耗费性能的)
- Using temporary:在许多查询的执行过程中,MySQL可能会借助
临时表
来完成一些功能,比如去重、排序之类的,比如我们在执行许多包含DISTINCT、GROUP BY、UNION等语句的查询过程中,如果不能有效利用索引来完成查询,MySQL很有可能寻求通过建立内部的临时表来执行查询。如果查询中使用到了内部的临时表,在执行计划的 Extra 列将会显示 Using temporary 提示 - Start temporary, End temporary:查询优化器会优先尝试将 IN 子查询转换成 semijoin ,而 semi-join 会有好多种执行策略,当执行策略为DuplicateWeedout时,也就是通过建立临时表来实现为外层查询中的记录进行去重操作时,驱动表查询执行计划的 Extra 列将显示 Start temporary 提示,被驱动表查询执行计划的 Extra列将显示 End temporary 提示
- LooseScan:在将In子查询转为semi-join时,如果采用的是LooseScan执行策略,则在驱动表执行计划的Extra列就是显示LooseScan提示
- FirstMatch(tbl_name):在将In子查询转为semi-join时,如果采用的是FirstMatch执行策略,则在被驱动表执行计划的Extra列就是显示FirstMatch(tbl_name) 提示
GROUP BY子句的查询中默认添加上ORDER BY子句,不想为包含 GROUP BY子句的查询进行排序,需要我们显式的写上ORDER BY NULL 在 EXPLAIN 单词和真正的查询语句中间加上 FORMAT=JSON,可以格式化为Json