mysql执行计划是sql语句经过查询优化器后,查询优化器会根据用户的sql语句所包含的字段和内容数量等统计信息,选择出一个执行效率最优(mysql系统认为最优)的执行计划,然后根据执行计划,调用存储引擎提供的接口,获取数据。
但是,在mysql执行的时候,到底使用了一个什么样的执行计划,有没有用到索引。当数据规模比较大的时候,sql执行的时候,执行计划不同,会直接影响sql的执行速度。这个时候,就需要对sql语句执行进行调试。
mysql我们在调试sql语句的时候,不会像我们写java或者其他语言代码那样通过打断点的方式进行代码调试。这个时候,我们就需要通过查看执行计划来调试我们的sql了。Mysql通过EXPLAIN来查看执行计划,我们写sql语句的时候,在语句之前加一个EXPLAIN就可以了。EXPLAIN可以用在SELECT、DELETE、INSERT、PEPLACE以及UPDATE等语句中,如:
1 EXPLAIN SELECT2 *3 FROM4 school5 WHERE6 school_nick = '县第一小学'
EXPLAIN SQL
执行后,结果如下:
这里介绍下每个字段以及每个字段的含义:
id
id是执行计划的标识符,是SELECT 查询的序号。如果结果集会跟其他表的结果用UNION关键字相结合,那么id可能为空。
id是否为空,对执行计划的影响不大,如果有兴趣可以看另外一篇博客:mysql执行计划id为空—UNION关键字,这里不再赘述。
select_type
select_type表示sql语句查询的类型。具体表示如下表:
select_type的值 | 含义 |
SIMPLE | 简单的select查询,没有使用关联和子查询。 |
PRIMARY | 最外层select,包含子查询的时候,最外层的查询 |
UNION | 在一个UNION查询中,第二次或以后的子查询操作 |
DEPENDENT UNION | 在一个UNION查询中,第二次子查询或以后的SELECT查询的时候需要依赖外部的查询 |
UNION RESULT | UNION的返回结果集 |
SUBQUERY | 子查询语句的第一个select语句 |
DEPENDENT SUBQUERY | 依赖外部查询的第一个子查询 |
DERIVED | 派生表——该临时表是从子查询派生出来的,位于form中的子查询 |
MATERIALIZED | 物化子查询(不确定啥意思,以后研究后再回来补充,或者大神指教) |
UNCACHEABLE SUBQUERY | 无法缓存结果的子查询,必须为外部查询的每一行重新计算 |
UNCACHEABLE UNION | UNION中的第二个或以后的不可缓存的子查询。 |
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不熟悉的同学,可以看以下代码:
1 -- 给test表的name字段加唯一索引,test2 的job 行添加非唯一索引。 2 -- 这个代码执行后,首先执行test2 的查询,查出job = ‘teacher’ 的所有集合。 3 -- 所以test2 的typ是ref 表示的是匹配job = ‘teacher’ 的一个结果集。 4 -- 然后从结果集中取出name的集合,去匹配test1.name的结果。因为test1.name是唯一索引,所以一个name最多匹配到一条记录,所以test的type是ref 5 EXPLAIN SELECT 6 * 7 FROM 8 test, 9 test210 WHERE11 test. NAME = test2. NAME12 AND test2.job = '33'
test ref and eq_ref
执行结果如下图:
5.fulltext 使用fulltext 索引进行查询。
6.ref_or_null 这种链接类型类似于ref,但是,除了ref之外,还对包含null的值进行了搜索。常用于解析子查询。代码示例如下:
1 SELECT * FROM ref_table2 WHERE key_column=expr OR key_column IS NULL;
ref_or_null
7.index_merge 这个链接类型表示使用索引合并优化。输出内容包含在索引列表中。
8.unique_subquery 索引查找,替换子查询,以提高效率。
value IN (SELECT primary_key FROM single_table WHERE some_expr)
unique_subquery
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(
半连接FirstMatch连接快捷方式策略用于tbl_name
)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 这意味着信息只用索引树中的信息检索出的,这比扫描整个表要快。
文章来源:http://www.cnblogs.com/liyasong/