MySQL 执行计划

EXPLAIN语句提供有关MySQL如何执行语句的信息。EXPLAIN与SELECT,DELETE,INSERT,REPLACE和UPDATE语句一块儿使用。优化

EXPLAIN为SELECT语句中使用的每一个表返回一行信息。它按照MySQL在处理语句时读取它们的顺序列出了输出中的表。 MySQL使用嵌套循环链接方法解析全部链接。这意味着MySQL从第一个表中读取一行,而后在第二个表,第三个表中找到匹配的行,依此类推。处理完全部表后,MySQL输出所选列,并经过表列表回溯,直到找到一个表,其中有更多匹配的行。从这个表中读取下一行,而后继续处理下一个表。spa

1.  EXPLAIN 输出列3d

说下几个关键的列:指针

  • type :链接类型
  • possible_keys :可选的索引
  • key :实际执行时使用的索引
  • ref :ref列显示将哪些列或常量与前面key列中显示的命名的索引进行比较以从表中选择行
  • rows :rows列表示MySQL认为执行查询必须检查的行数

2.  链接类型code

链接类型,顺序从最好到最差,依次是: orm

systemblog

表只有一行。这是const join类型的特例。排序

const索引

表最多有一个匹配行,在查询开始时读取。由于只有一行,因此这一行中的列的值能够被优化器的其他部分视为常量。const表很是快,由于它们只被读取一次。it

当你用PRIMARY KEY或UNIQUE索引的全部部分与常量值进行比较时,将使用const。

例如,下面的表tbl_name能够被当作const表:

SELECT * FROM tbl_name WHERE primary_key=1;
SELECT * FROM tbl_name WHERE primary_key_part1=1 AND primary_key_part2=2;

eq_ref

对于前表中的每一行组合,从这个表中读取一行。除了system和const类型,这是可能的最好的联接类型。当一个索引的全部部分都被联接使用而且索引是PRIMARY KEY或UNIQUE NOT NULL索引时,使用它。

eq_ref能够用于使用=操做符进行比较的索引列。比较值能够是一个常量,也能够是使用在此表以前读取的表中的列的表达式。

例如,下面的例子中MySQL可使用eq_ref链接来处理ref_table:

SELECT * FROM ref_table,other_table
  WHERE ref_table.key_column=other_table.column;

SELECT * FROM ref_table,other_table
  WHERE ref_table.key_column_part1=other_table.column AND ref_table.key_column_part2=1;

ref

对于前表中的行的每种组合,将从该表中读取具备匹配索引值的全部行。若是联接仅使用key的最左前缀,或者若是key不是PRIMARY KEY或UNIQUE索引(换句话说,若是联接没法基于key值选择单个行),则使用ref。若是使用的key仅匹配几行,则这是一种很好的联接类型。

ref可用于使用=或<=>运算符进行比较的索引列。

例如,下面的例子中,MySQL能够用ref链接来处理ref_table:

SELECT * FROM ref_table WHERE key_column=expr;

SELECT * FROM ref_table,other_table
  WHERE ref_table.key_column=other_table.column;

SELECT * FROM ref_table,other_table
  WHERE ref_table.key_column_part1=other_table.column
  AND ref_table.key_column_part2=1;

fulltext

使用FULLTEXT索引执行链接

ref_or_null

这种链接类型相似于ref,可是MySQL会额外搜索包含NULL值的行。此联接类型优化最经常使用于解析子查询。

例如,下面的例子中,MYSQL可使用ref_or_null来处理ref_table:

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

index_merge

这种链接类型代表使用了索引合并优化。在这种状况下,输出行中的key列包含使用的索引列表,而key_len包含所使用索引的最长key部分列表。

unique_subquery

此类型将eq_ref替换为如下形式的某些IN子查询:

value IN (SELECT primary_key FROM single_table WHERE some_expr)

index_subquery

与unique_subquery相似,它代替了IN子查询,但适用于如下形式的子查询中的非惟一索引:

value IN (SELECT key_column FROM single_table WHERE some_expr)

range

只检索给定范围内的行,并使用索引来选择行。输出行中的key列指示使用了哪一个索引。key_len包含所使用的最长的key部分。对于这种类型,ref列为NULL。

使用=,<>,>,> =,<,<=,IS NULL,<=>,BETWEEN,LIKE或IN()运算符将key列与常量进行比较时,可使用range:

SELECT * FROM tbl_name WHERE key_column = 10;

SELECT * FROM tbl_name WHERE key_column BETWEEN 10 and 20;

SELECT * FROM tbl_name WHERE key_column IN (10,20,30);

SELECT * FROM tbl_name WHERE key_part1 = 10 AND key_part2 IN (10,20,30);

index

index链接类型与all是同样的,区别在于index链接类型扫描的时候索引树。一般,只发生在如下两种状况:

  • 若是索引是查询的覆盖索引,而且可用于知足表中所需的全部数据,则仅扫描索引树。在这种状况下,“Extra”列显示“Using index”。仅索引扫描一般比ALL快,由于索引的大小一般小于表数据。
  • 使用从索引读取数据以按索引顺序查找数据行来执行全表扫描。“Uses index”不会出如今Extra列中。

ALL

对前表的行的每一个组合进行全表扫描。若是该表是未标记为const的第一个表,则一般很差,而且在全部其余状况下一般很是糟糕。一般,能够经过添加索引来避免ALL,这些索引容许基于早期表中的常量值或列值从表中检索行。 

3.  Extra列

关于Extra列的输出,只说几个常见的:

Using filesort

MySQL必须作一次额外操做,以找出如何按排序顺序检索行。排序是经过根据联接类型遍历全部行并存储与WHERE子句匹配的全部行的排序key和指向该行的指针来完成的。而后对key进行排序,并按排序顺序检索行。

Using index

仅使用索引树中的信息从表中检索列信息,而不须要执行额外的查找来读取实际行。当查询只使用属于单个索引的列时,可使用此策略。

Using temporary

为了解析查询,MySQL须要建立一个临时表来保存结果。一般,若是查询包含以不一样方式展现列的GROUP BY和ORDER BY子句,则会发生这种状况。

Using where 

WHERE子句用于限制哪些行匹配下一个表或发送给客户端。除非你打算从表中获取或检查全部行,不然若是额外的值没有使用where,而且表链接类型是all或index,则查询中可能出现错误。 

4.  优化ORDER BY

在某些状况下,MySQL可能会使用一个索引来知足ORDER BY子句,从而避免执行filesort操做所涉及的额外排序。

假设在(key_part1, key_part2)上有一个索引,下面的查询可使用索引来解析ORDER BY部分。优化器是否真的这样作,取决于若是还必须读取索引以外的时,读取索引是否比表扫描更有效。

SELECT * FROM t1 ORDER BY key_part1, key_part2;

上面的语句,查询使用SELECT *,这可能会选择比key_part1和key_part2更多的列。在这种状况下,扫描整个索引并查找表行以查找索引中未包含的列可能比扫描表并排序结果要昂贵。若是是这样,则优化器不太可能使用索引。若是SELECT *仅选择索引列,则使用索引并避免排序。

下面这个查询中,key_part1是常量,所以经过索引访问的全部行都按key_part2顺序排列,而且若是WHERE子句的选择性足以使索引范围扫描比表扫描便宜,则在(key_part1,key_part2)上的索引能够避免排序:

SELECT * FROM t1 WHERE key_part1 = constant ORDER BY key_part2; 
相关文章
相关标签/搜索