Mysql执行计划说明
Mysql执行计划翻译:
官网原文请见http://dev.mysql.com/doc/refman/5.6/en/explain-output.html:5.6
EXPLAIN语句提供有关SELECT语句的执行计划信息。
EXPLAIN返回在SELECT语句中使用的每个表的一行有关信息。它列出的表中的顺序是,依照MySQL在处理语句时读取他们的次序。 MySQL处理所有联接的方法是使用嵌套循环连接(nested loop join)。这意味着它们的MySQL读取第一表中的一行,然后发现在第二个表,第三表依次找出匹配行(扫表),依此类推。当所有的表处理完(第一次),MySQL的输出选中的列和通过回溯表直到有表被发现其中有更多的匹配行。下一行被从该表中读出并且该过程继续进行下一个表匹配。
执行计划输出列:
.id
SELECT识别符,这是SELECT查询语句中的序列号,数字越大,优先执行。如果这行是和其他行合并的结果,这个值可以为null。比如:使用 UNION 关键字,将多个select 的结果合并到一起。
.Select_type
Dependent通常意味着使用相关子查询的。
Dependent SUBQUERY计算不同于不可缓存SUBQUERY计算。Dependent子查询中,子查询为从它的外环境变量不同值的每个集合重新计算一次。对于不可缓存的子查询中,子查询重新计算外部环境中的每一行。
.table
输出所用到的表(PS:通过id 联系)
1.<union M,N>
: The row refers to the union of the rows with id
values of M and N;
2.<derived N>
: The row refers to the derived table result for the row with an id
value of N. A derived table may result, for example, from a subquery in the From
clause.
3.<subquery N>
: The row refers to the result of a materialized subquery for the row with an id
value of N.
.partition
查询所匹配到的记录在这分区中。显示此列仅当使用分区。该值为NULL的非分区。
.type
EXPLAIN输出的类型列描述了表如何连接。下面的列表描述了连接类型,从最好到最坏的次序。
1.system:该表只有一行(=系统表)。这是一个特例常量联接类型。
2.const: 该表至多有一个匹配行,并且被读取在查询的开始。因为只有一个匹配行,从该行中的列值被的其余优化部分被视为常数。常量表很快,因为它们只读取一次。
当你比较PRIMARY KEY或UNIQUE索引或者他们的一部分和一个常量时使用。在以下的查询,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;
3.eq_ref:从该表中读出一行,用于和前面的表中读取的行每一种组合。除了系统和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
从该表读取的相匹配的索引值的所有行和先前的表行的每个组合。ref使用在连接使用索引的一个最左前缀,如果该键不是PRIMARY KEY或唯一索引(换句话说,如果联接不能基于键值选择出单行)。如果所使用的索引匹配只有几行,这是一个良好的连接类型。
red可以用于那些使用=或<=>操作比较索引列。在下列实施例中,MySQL可以使用一个参考连接来处理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:该方式使用的是全文检索
.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::索引合并优化(PS:多个索引条件情况,进行条件的合并优化)
SELECT * FROM tbl_name WHERE key1 = 10 OR key2 = 20; SELECT * FROM tbl_name WHERE (key1 = 10 OR key2 = 20) AND non_key=30; SELECT * FROM t1, t2 WHERE (t1.key1 IN (1,2) OR t1.key2 LIKE 'value%') AND t2.key1=t1.some_col; SELECT * FROM t1, t2 WHERE t1.key1=1 AND (t2.key1=t1.some_col OR t2.key2=t1.some_col2);
.unique_subquery
这种类型替换ref对于一些在下面的表单子查询
value IN (SELECT primary_key FROM single_table WHERE some_expr)
.index_subquery
该联接类型类似于unique_subquery。它取代了unqiue_subquery,但它在以下形式的子查询非唯一索引:
value IN (SELECT key_column FROM single_table WHERE some_expr)
.range
仅是在给定的范围的行检索,使用索引来选择行。输出行中的键column指示使用哪个索引。该key_len包含所使用key最长的关键部分。ref列为NULL。
当一个键列的范围可以使用和常量的任何的=,<>,>,>=,<,<=,IS NULL,<=>,BETWEEN或IN()操作符:
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相同相同的,除了索引树被扫描。发生这种情况有两种方法:
1:如果该index是用于查询覆盖索引,可以满足表中所需的所有数据,只要索引树被扫描。在这种情况下,Extra
column表示使用索引。仅索引扫描通常比ALL快,因为索引块的大小通常比 表数据小。
2. 全表扫描通过走索引读取查找数据行的顺序。Uses index不会出现在Extra列。
MySQL能使用这种连接类型时查询仅使用单个index的一部分列。
.All
全表扫描完成从先前的表的行的每个组合。这通常不是一件好事,如果表是第一个表没有标明const,通常在所有其他情况下很差。通常情况下,你可以通过添加索引,使行检索基于从早期的 表常数值或列值避免ALL;
.Extra
:包含mysql 解析查询的额外信息。
Distinct:mysql 查询不同的行,当找到和当前行匹配的时候,就不再搜索了。
FirstMatch(tbl_name) :The semi-join FirstMatch join shortcutting strategy is used for tbl_name
.
Full scan on NULL key:查询分析器无法使用当前索引的一个失败策略。
Impossible HAVING: where 条件总是false,无法筛选任何行
Impossible WHERE noticed after reading const tables:和上面类似
LooseScan:利用索引来扫描一个子查询表可以从每个子查询的值群组中选出一个单一的值。
Not exists:mysql 优化了left join 的查询,
比如:SELECT * FROM t1 LEFT JOIN t2 ON t1.id=t2.id WHERE t2.id IS NULL;
假设t2.id 定义为 not null,这种情况下,Mysql 扫描t1 并且用t1.id 在t2中查找行,如果Mysql 在t2中找到匹配的行,它表明t2.id 不可能为null,因此不会扫描剩下的具有相同id的行,换句 话说,t1 中的每一行,mysql 每次都在t2中做一下查询,无论t2 有多少匹配。
Using filesort:无法利用索引完成的排序,比如文件排序
Using index:利用索引树扫描得出结果,不用全部扫描
Using temporary:利用临时表存储结果集,通常查询包含 GROUP BY
and ORDER BY
。
Using where:使用where 限定那些行于下一张表匹配,或者返回到客户端,除非你想要获取or 检查表中所有行,如果extra 的值不是Using where并且连接类型不是all 或者index ,那么 你可能有一些错误在你的查询中。
Using join buffer:
Using MRR:有点复杂,
Key
:key 这一列表明实际你用的是那一个索引,没有则是null
Key len
:该列是Mysql 使用key 的长度,没有则为null,文档提示这值能确定你 multiple-part key 中使用的是哪一部分。
Rows
:表示Mysql 执行语句扫描的行数
Possible_keys
:表示mysql 找到的这些行数据,在indexes(很多索引)里面的哪一个。查询涉及到的字段上若存在索引,则该索引将被列出,但不一定被查询使用。如果是空的,没有相关的 索引。这时要提高性能,可通过检验WHERE子句,看是否引用某些字段,或者检查字段不是适合索引。