mysql最新版explain详解来自官网直译(3)

来源:互联网 发布:3dmax是什么软件 编辑:程序博客网 时间:2024/06/05 06:42
Explain的连接类型
EXPLAIN输出的type列的值说明了表是怎么样连接的。在以JSON格式的输出中,该列的值为access_type属性的值。下面从最好到最差的连接类型来说说明:
system:表中只有一行数据的表,这也是一种特别类型的常数连接类型
const:在执行查询开始的时候,大多数都只有一行是匹配成功的。因为是单行匹配,所以需要查找该行对应列的值可以被优化器看做是常数。常数表因为只读一次,所以非常快。
当你通过常量值去和主键索引或者唯一索引比较的时候,通常使用的就是const。在下面的查询中,tb1_name能够被作为const表:
select * from tb1_name where primary_key=1;
select * from tb1_name tb1_name where primary_key_part1=1 and primary_key_part2=2;
eq_ref:于来自已有表查询结果集中的每一次比较都只有一行被读取。除了system和const类型的连接,这是最佳的连接类型。当连接使用了主键索引或者是唯一非null索引的全部来连接数据的时候,该连接使用的就是eq_ref连接。
当在索引列上使用=来对比时使用的就是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 where key_column_part1=other_table.column and ref_table.key_column_part2=1
ref:从之前表中获取的值的匹配都是该表中索引值的全部行。如果连接使用的仅仅是左前缀的索引或者是索引并不是一个主键索引、一个唯一索引(换句话说,该连接在基于索引的查询中不能选择出一个简单的行),那么使用的就是ref连接。如果这个索引是的匹配出的仅仅是很少一部分行,这是一个好的连接。
在索引列上使用=或者是<=>操作时,ref连接会被使用。在下面的例子中,mysql能够在表ref_table中使用ref连接。
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.keey_column_part2=1;
fulltext:通过使用一个fulltext索引来完成连接。
ref_or_null:该类型和ref类似,但是mysql需要做额外的查询包含null值的行。这种连接类型的优化大多数情况被用在解决子查询中。在下面的例子中,mysql在表ref_table中使用ref_or_null连接;
select * from ref_table where key_column=expr or key_column is null;
请看8.2.1.12关于等于null的优化。
index_merge:这种连接类型说明优化使用了索引合并。在这种情况下,输出的列中包含了多个索引列,并且key_len的值为所使用索引列中最长索引列的长度。关于更多信息请看8.2.1.3的索引合并的优化
unique_subquery:在如下包含in子查询条件的查询形式中取代eq_ref来完成查询:value in(select primary_key from
 single_table where some_expr)。unique_subquery仅仅是一个索引查询函数,这与完整的子查询来说,其更有效。
index_subquery:类似于unique_subquery的连接类型。他以如下的形式作用在非唯一索引列的子查询中取代含in关键字的子查询
value in(select key_column from single_table where some_expr)
range:在使用一个索引查询时,仅仅需要找到被给出区域的行。在输出的属性列中说明了哪个索引被使用。key_len的值是被使用的最长索引的部分。对于这种类型ref列的值为null。
当被对比的索引列条件中包含了=,<>,>,>=,<,<=,IS NULL,<=>,BETWEEN,或者IN()操作时,就会使用range类型的连接。例如:
select * from tb1_name where key_column=10;
select * from tb1_name where key_column BETWEEN 10 AND 20;
select * from tb1_name where key_column IN (10,20,30);
select * from tb1_name where key_part1=10 and key_part2 in(10,20,30);
index:index连接类型和ALL连接类型相同,要求扫描索引树。如下两种情况下会使用这中连接:
1)如果索引是一个覆盖索引并且仅仅查找索引树就可以得到要从表中查找的全部数据。在这种情况下,额外的列也是使用索引来查找。一个仅仅扫描索引的查询通常比全表扫描更快,因为索引的大小通常比表数据小很多。
2)按照索引中存储的数据列的顺序来完成全表数据的扫描。使用的索引不会出现在Extra列中。
mysql能够使用这种连接,当查询使用的列只是一个简单索引的部分数据的时候。
ALL:对于已有表中数据的行每一次都是全表扫描。如果第一张表没有标记为const,这通常来说不是个好现象,并且在某些情况下是很糟糕的情况。正常来说,你可以通过给基于常数值或者是更早表中的列值来加索引来避免ALL类型的连接出现。


EXPLAIN额外信息的说明。
关于mysql如何解析查询的一些额外信息被展示在Extra列中。接下来将说明该列中可能出现的值。而对于JSON格式则是已属性的值来展示Extra的值。其中部分比较特殊,其他的都是已文本形式的message属性来展示。
如果你想要你的查询尽可能的快速,找出Extra列的值是Using filesort和Using temporary,或者在Json格式下应该是找出using_filesort和using_temporary_table两属性,他们是等价的。
Child of 'table' pushed join@1(JSON:message text):该表作为子表被引用在一个连接中,能够被压进NDB的内核。只有在NDB集群中,压进连接才能够被使用。查看ndb_join_pushdown服务系统的系统变量描述来了解更多信息和举例。
const row not found(JSON property:const_row_not_found):表是空的,对于像select ....from tb1_name这样的查询。
Deleting all rows(JSON property:message):对于删除来说,一些存储引擎(例如myisam)是支持手动删除表中数据的方法的,而且是简单快速的方法。如果引擎使用了这种优化,那么Extra列的值就会展示。
Distinct(JSON property:distinct):mysql是查找不同的值,所以当引擎找到于当前行匹配的第一行时,不再会继续为当前行查找剩下的没有比对的行。
FirstMatch(tb1_name)(JSON property:first_match):半连接FirstMatch简化策略被用在了tb1_name中。
Full scan on NULL key(JSON property:message):当查询优化器不能使用索引查询时,对于子查询优化的后补查询方案将会被使用。
impossible HAVING(JSON property:message):HAVING条件过滤没有效果,或者是始终选不出任何列(理解为返回已有查询的结果集)。
impossible WHERE(JSON property:message):WHERE条件过滤没有效果,或者是始终选不出任何列(理解为最终是全表扫描)。
impossible WHERE noticed after reading const tables(JSON property:message):mysql在查询了所有const(常量表和系统表)并且发现WHERE查询条件不起作用。
LooseScan(m..n)(JSON property:message):semi-join LooseScan的机制被使用。m 和n是索引部分的数量
No matching min/max row(JSON property:message):没有满足查询条件的列,例如SELECT MIN(...) FROM ...WHERE condition.
no matching row in const table(JSON property:message):对于一个连接查询,没有满足唯一索引条件的列或者是表为空表。
No matching rows after partition pruning(JSON property:message):对于删除或者更新,除去分区之后,优化器发现没有可以删除或更新的数据。它和对于查询的impossible WHERE 是等价的。
No tables used(JSON property:message):查询只有一个from dual条件,没有关于真实表的from条件。对于插入或者取代语句,当没有select部分时,Explain会展示该值。例如,执行EXPLAIN INSERT INTO t VALUES(10)的时候会出现,因为该语句和EXPLAIN INSERT INTO t SELECT 10 FROM DUAL是一样的。
Not exists(JSON property:message):mysql能够在一个查询中使用一个left join优化并且对于左连接的准则,当从该表中找到一行数据与已经找出的数据行对应,则不再查找更多的行。;例如下面的查询可以使用这种优化。
select * from t1 left join t2 on t1.id=t2.id where t2.id is null;
假设t2.id被定义为非null,在这种情况下,mysql扫描t1并且使用t1.id列的值查找t2表中的行。如果mysql在t2表中找到了行,如果mysql知道t2.id不可能是null,那么mysql将不会继续查找t2表中剩余的其他有相同id值的行。换句话说,对于在t1表中的每一行,mysql需要做的仅仅是在t2表中做一个简单的查询,而不需要在意t2表中到底有多少行能够与其对应。
Plan isn't ready yet(JSON property:none):这个值的产生在EXPLAIN FOR CONNECTION,当优化器不能按照被命名的查询连接来创建一个执行器计划时。如果执行计划的输出包含了多行,所有行都可以有该值,完全取决于优化器来决定完整的执行计划。
Range checked for each record(index map:M)(JSON property:message):mysql没有发现可以使用的很好的索引,但是发现一些索引也许能使用在已有表的列值上。对于已有表格数据的每一行比较,mysql检查是否可以使用range或者index_merge方法来检查行。这不是最快的,但是比完全不用索引要快很多。标准可用性在8.2.1.2的range优化和8.2.1.3的索引合并优化里有描述。
特别是在全部列值都是已知并且是常量的情况下。
索引被限制了必须以1来开头,并且同样的顺序展示在表的show INDEX中。如果索引map的值N是一个位屏蔽值也就是说索引是候选项。
例如一个值是0x19(二进制对应为11001)意味着索引1,4,5将会被考虑。
Scanned N databases(JSON property:message):这说明了服务器完成了多少直接扫描,在完成一个关于INFORMATION_SCHEMA表的查询时,具体的描述在8.2.3的优化INFORMATION_SCHEMA 查询。关于N的值可以是0,1,或者是all.
Select table optimized away(JSON property:message):优化器决定1)最多一行数据被返回,2)并且产生这行,确定在集合中的数据必须要被查看。当通过优化器选择必须要读取的行数据读取时,通过执行查询不需要多去其他任何表。
条件1将被满足,当查询中暗含了聚合分组(如包含了聚合函数,但不是group by)。条件2将被满足,当每次使用索引都能够查找一行数据。读取索引的数目决定了要读取的行数。例如下面的查询语句暗含了分组的存在:select MIN(c1),MIN(c2) from t1;
假如Min(c1)能够通过读取一个索引列来取到,并且MIN(c2)能够通过读取另外的索引来获取。也就是每一列c1和c2,存在一个索引是第一列的索引。在这种情况下,一行将被返回,通过读取到的两行决定性的数据中。
这个Extra的值不会生成,如果读取到的行不能被确定的话,比方说:select MIN(c2) from t1 where c1<=10;
假设(c1,c2)是一个覆盖索引。使用这个索引,所有c1<=10的行米线被读取从而用于找出c2列中值最小的行。通过对比,考虑如下的查询:
select MIN(c2) from t1 where c1=10;
在这种情况下,第一索引中满足条件c1=10的行中保护了c2列中最小值的行,为了得到c2的最小值,也就只有一行数据是必须要读取的。对于存储引擎中包含了一个准确行数的计算对于每张表(比方说myisam,但innoDB中没有),这个Extra值能够发生当统计count(*)查询并且没有where条件或者一直是true,并且也没有group by查询条件。(这是一个暗含了分组查询的例子,存储引擎来决定是否一个决定性数目的行能够被读取)
Skip_open_table,Open_frm_only,Open_full_table(JSON property:message):这个值表明应用了file-opening优化在查询INFORMATION_SCHEMA表中,具体描述在8.2.3中的优化INFORMATION_SCHEMA查询。
Skip_open_table:表文件不需要打开。通过扫描数据库目录就可以获取查询需要的可用信息。
Open_frm_only:只有表中以.frm结尾的文件需要打开。
Open_full_table:未优化的信息查询。.frm,.MYD,.MYI文件都需要打开。
start temporary,End temporary(JSON propery:message):这说明在半连接复制清除策略中使用了临时表。
unique row not found(JSON property:message):对于查询类似于select .... from tb1_name,通过表中的唯一索引或者主键索引找不到满足条件的列。
Using filesort(JSON property:using_filesort):mysql必须做一个额外的方法来找出怎么比较已经排好序的列。有序是通过连接类型,存储的排序关键字和where条件查询等一起确定的。被用来排序的关键字和被用来查询的行都是有序的,具体请看8.2.1.13的优化ORDER BY 查询。
Using index(JSON property:using_index):从表中获取列信息仅仅通过索引树,而不需要额外去读取真实的行数据。如果查询使用的列值仅仅是一个简单索引的部分值,则会使用这种策略来优化查询。对于innoDB数据库中的表有一个自定义的聚簇索引,该索引能够起作用,即使是Using index并没有出现在Extra列中。这种情况下的type字段为index并且key字段的值为PRIMARY。
Using index condition(JSON property:using_index_condition):表的读取首先通过读入索引值来判断是否需要权标扫描。在这种方式中,如果有需要的话。索引信息将被用来服务(压入)全表扫描的。具体请看8.2.1.5的优化索引条件的压入操作。
Using index for group-by(JSON property:using_index_for_group_by):类似于Using index的表查询方法,既mysql发现一个索引能够被用来查找所有列对于group by或者是DISTINCT查询,而不需要任何真实的表查询。另外,索引使得查找每一个分组都更有效,只有少量的索引值需要读取。更多信息内容请看8.2.1.14的group by 的优化.
Using join buffer(Block Nested Loop),Using join buffer(Batched key Access)(JSON property:using_join_buffer):从已有连接中找到的数据的部分被读入了连接缓存,并且通过缓存来完成与当前表的连接。(Block Nested Loop)说明使用了块循环算法,(Batched key Access)说明使用了批量接入关键字算法。也就是说,从已经查找过的表中要输出的列会被缓存,并且会批量的找出与当前表比较,这时就会出现Using join buffer。在JSON格式的输出中,using_join_buffer的值要么是Block Nested Loop,要么是Batched Key Access.
Using MRR(JSON property:message):通过使用多个范围读取的优化策略来读取表中数据。具体情看8.2.1.10的多范围读取的优化。
Using sort_union(...),Using union(...),Using intersect(...)(JSON property:message):这个说明了在index_merge的连接类型中索引合并是怎么样完成的,使用了什么特别的算法。具体请看8.2.1.3的索引合并的优化。
Using temporary(JSON property:using_temporary_table):为了执行查询,MySQL需要创建一个临时表来存储已有的结果。如果你的查询中有group by和order by 条件并且是不同的列,则会有该类型产生。
Using Where(JSON property:attached_condition):一个where条件被用来选择那些列需要与接下来的表匹配或者是返回给客户端。除非你特区趋向于全表扫描,否则如果你的表连接类型是ALL或者是index,而且在Extra列的值中没有Using Where,那说明你的查询中应该是有些错误的地方需要修改。Using where 不会直接对应JSON格式的输出,而是通过attached_condition属性列的值包含了查询中使用的任何where条件。
Using where with pushed condition(JSON property:message):这个只能在NDB的表中可以用。这说明了NDB集群中使用了条件pushdown优化去提高直接比较两个没有索引列的效率。在这种情况下,有pushed down条件的集群数据节点和其他数据一起查找。这样保证了通过网络只发送有用的数据,并且可以提高5-10倍的速度比不使用优化的情况下。关于更多消息,请看8.2.1.4的Engine Condition Pushdown Optimization".

Zero limit(JSON property:message):查询条件中有limit 0 并且没有可以选择的任何行。

到此关于Extra列的详解和JOIN type的详解就结束了,接下来我们要写的是对于执行计划的举例说明。

原创粉丝点击