MySQL中SQL执行计划详解

MySQL执行计划是sql语句经过查询优化器后,查询优化器会根据用户的sql语句所包含的字段和内容数量等统计信息,选择出一个执行效率最优(MySQL系统认为最优)的执行计划,然后根据执行计划,调用存储引擎提供的接口,获取数据。

但是,在MySQL执行的时候,到底使用了一个什么样的执行计划,有没有用到索引。当数据规模比较大的时候,sql执行的时候,执行计划不同,会直接影响sql的执行速度。这个时候,就需要对sql语句执行进行调试。

MySQL我们在调试sql语句的时候,不会像我们写java或者其他语言代码那样通过打断点的方式进行代码调试。这个时候,我们就需要通过查看执行计划来调试我们的sql了。MySQL通过EXPLAIN来查看执行计划,我们写sql语句的时候,在语句之前加一个EXPLAIN就可以了。EXPLAIN可以用在SELECT、DELETE、INSERT、PEPLACE以及UPDATE等语句中,如:

EXPLAIN SELECT
    *
FROM
    school
WHERE
    school_nick = '县第一小学'

EXPLAIN SQL

执行后,结果如下:

MySQL中SQL执行计划详解

这里介绍下每个字段以及每个字段的含义:

id

id是执行计划的标识符,是SELECT 查询的序号。如果结果集会跟其他表的结果用UNION关键字相结合,那么id可能为空。

id是否为空,对执行计划的影响不大。

select_type

select_type表示sql语句查询的类型。具体表示如下表:

select_type的值          含义
SIMPLE简单的select查询,没有使用关联和子查询。
PRIMARY最外层select,包含子查询的时候,最外层的查询
UNION在一个UNION查询中,第二次或以后的子查询操作
DEPENDENT UNION在一个UNION查询中,第二次子查询或以后的SELECT查询的时候需要依赖外部的查询                         
UNION RESULTUNION的返回结果集
SUBQUERY子查询语句的第一个select语句
DEPENDENT SUBQUERY                                 依赖外部查询的第一个子查询
DERIVED派生表——该临时表是从子查询派生出来的,位于form中的子查询
MATERIALIZED物化子查询(不确定啥意思,以后研究后再回来补充,或者大神指教)
UNCACHEABLE SUBQUERY     无法缓存结果的子查询,必须为外部查询的每一行重新计算
UNCACHEABLE UNIONUNION中的第二个或以后的不可缓存的子查询。

table


  输出行引用的表的名称。一般为表格名称或别名,也可能为如下值:

1.UNION的并集结果集。

2.derivedN当前行指向派生结果集。可能是一个派生表,例如来自FROM子句的结果集。

3.subqueryN 当前行指向一个子查询的结果集。

type


  连接类型。该列输出表示如何连接表。下面的类型表示从最好的到最坏的类型

1.system 该表只有一行(=系统表)。这是const连接类型的特例 。

2.const 最多只有一行匹配,在查询开始的时候,计算出常量对应的地址,直接访问,例如:select * from test where  name ='zhang' 当name是唯一索引的时候,就有可能出现const。const非常快,因为它只读一次。

3.eq_ref 除了 system和 const类型之外,这是最好的连接类型。当两个表联查时使用索引的所有部分(针对的是组合索引),且索引是 主键或唯一索引时使用它。使用“=”运算符来进行索引列的比较。

4.ref 非唯一索引扫描,返回某个匹配值的所有行。常用语非唯一索引。这里对于eq_ref 和ref不熟悉的同学,可以看以下代码:

-- 给test表的name字段加唯一索引,test2 的job 行添加非唯一索引。
-- 这个代码执行后,首先执行test2 的查询,查出job = ‘teacher’ 的所有集合。
-- 所以test2 的typ是ref 表示的是匹配job = ‘teacher’ 的一个结果集。
-- 然后从结果集中取出name的集合,去匹配test1.name的结果。因为test1.name是唯一索引,所以一个name最多匹配到一条记录,所以test的type是ref
EXPLAIN SELECT
    *
FROM
    test,
    test2
WHERE
    test. NAME = test2. NAME
AND test2.job = '33'

test ref and eq_ref

执行结果如下图:

MySQL中SQL执行计划详解

5.fulltext 使用fulltext 索引进行查询。

6.ref_or_null 这种链接类型类似于ref,但是,除了ref之外,还对包含null的值进行了搜索。常用于解析子查询。代码示例如下:

SELECT * FROM ref_table
WHERE key_column=expr OR key_column IS NULL;

7.index_merge 这个链接类型表示使用索引合并优化。输出内容包含在索引列表中。

8.unique_subquery 索引查找,替换子查询,以提高效率。

value IN (SELECT primary_key FROM single_table WHERE some_expr)

9. index_subquery 类似于unique_subquery 但是替换in子查询,适用于非唯一索引,代码: value IN (SELECT key_column FROM single_table WHERE some_expr)

10.range 扫描部分索引,对索引的扫描从某一点开始,返回的是某个索引区域的值。常见的有基于索引的 < ,> 等的查询。

11. index 扫描全部索引,对索引进行整体扫描。

12.all 全表扫描,最慢的查询 。应该避免

  possible_keys

可能使用的key,指出当前查询涉及到的行都含有那些索引。如果有索引就会列出,但是不一定会被使用。

key

实际使用的索引。如果没有使用索引,显示null。

  key_len

表中对应的索引最大可能长度。可以通过设置索引长度改变该值。例如:一个varchar(255)的索引长度为255,可是我们使用不到那么长,我们可以取字符串的前五位作为索引。这时key_len 就是5.这里关于索引值的长度的选取规则,以后有机会再写一篇博客详细介绍。

ref

哪些字段和key一起被使用。没用过。

rows

受影响的行数。不是特别精确的。

Extra

解释额外的信息。包含mysql对于query优化的时候的一些附加信息。非常有用。可能出现的结果如下:

  • const row not found 该表为空
  • Deleting all rows  表格内数据被标记删除,正在删除中(某些存储引擎支持一种方法,以简单快捷的方式删除所有行,这时查询就会出现这个提示)
  • 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)表,并注意到该WHERE子句始终为false。
  • No matching min/max row 没有行满足查询的条件的行
  • no matching row in const table  对于具有连接的查询,有一个空表或没有满足唯一索引条件的行的表。
  • No matching rows after partition pruning  对于DELETE或 UPDATE,优化器在分区修剪后发现没有删除或更新的内容。
  • No tables used 查询没有FROM子句
  • Not exists 查询的内容不存在
  • Plan isn't ready yet 优化程序尚未完成为在命名连接中执行的语句创建执行计划时, 会出现此值。
  • Range checked for each record MySQL发现没有好的索引可以使用,但发现在前面的表的列值可能会使用某些索引。
  • Recursive  递归
  • Skip_open_table, Open_frm_only, Open_full_table
    • Skip_open_table:表文件不需要打开。该信息已从数据字典中获得。
    • Open_frm_only:只需要读取表信息的数据字典。
    • Open_full_table:未优化的信息查找。必须从数据字典中读取表信息并读取表文件。
  • unique row not found  对于查询,没有行满足 索引或表的条件。
  • Using filesort  使用文件排序。MySQL必须执行额外的传递以找出如何按排序顺序检索行。排序是通过根据连接类型遍历所有行并将排序键和指针存储到与该WHERE子句匹配的所有行的行来完成的。然后对键进行排序,并按排序顺序检索行
  • Using index 仅使用索引树中的信息从表中检索列信息,而不必另外寻找读取实际行。当查询仅使用属于单个索引的列时,可以使用此策略。
  • Using index condition  通过首先访问索引,确定是否可以读取完整的表行。
  • Using index for group-by  使用索引分组。表示MySQL找到了一个索引,可用于检索GROUP BY或 DISTINCT查询的所有列,而无需对实际表进行任何额外的磁盘访问。此外,索引以最有效的方式使用,因此对于每个组,只读取少数索引条目。
  • Using index for skip scan  使用索引跳过扫描范围
  • Using join buffer  将表数据读入缓存,然后从缓存中读数据来执行操作。
  • Using MRR 使用多范围读取优化策略读取表。
  • Using temporary 使用临时表,MySQL需要创建一个临时表来保存结果。如果查询包含以不同方式列出列的GROUP BY和 ORDER BY子句,则通常会发生这种情况。
  • Using where  使用上了where限制,表示MySQL服务器在存储引擎受到记录后进行“后过滤”(Post-filter),如果查询未能使用索引,Using where的作用只是提醒我们MySQL将用where子句来过滤结果集。
  • Zero limit  查询有一个LIMIT 0子句,不能选择任何行。
  • Only index  这意味着信息只用索引树中的信息检索出的,这比扫描整个表要快。 

相关推荐