您的位置:首页 > 数据库 > MySQL

MYSQL语句调优:MYSQL Explain 执行计划输出详解

2014-12-19 11:28 921 查看
在 explain的帮助下,您就知道什么时候该给表添加索引,以使用索引来查找记录从而让select 运行更快。

如果由于不恰当使用索引而引起一些问题的话,可以运行 analyze table来更新该表的统计信息,例如键的基数,它能帮您在优化方面做出更好的选择。

explain 返回了一行记录,它包括了 select语句中用到的各个表的信息。这些表在结果中按照mysql即将执行的查询中读取的顺序列出来。mysql用一次扫描多次连接(single- sweep,multi-join)的方法来解决连接。这意味着mysql从第一个表中读取一条记录,然后在第二个表中查找到对应的记录,然后在第三个表
中查找,依次类推。当所有的表都扫描完了,它输出选择的字段并且回溯所有的表,直到找不到为止,因为有的表中可能有多条匹配的记录下一条记录将从该表读 取,再从下一个表开始继续处理。

在mysql version 4.1中,explain输出的结果格式改变了,使得它更适合例如 union语句、子查询以及派生表的结构。更令人注意的是,它新增了2个字段: id和 select_type。当你使用早于mysql4.1的版本就看不到这些字段了。

explain结果的每行记录显示了每个表的相关信息,每行记录都包含以下几个字段:

id

本次 select 的标识符。在查询中每个 select都有一个顺序的数值。

select_type

select 的类型,可能会有以下几种:

simple: 简单的 select (没有使用 union或子查询)

primary: 最外层的 select。

union: 第二层,在select 之后使用了 union。

dependent union: union 语句中的第二个select,依赖于外部子查询

subquery: 子查询中的第一个 select

dependent subquery: 子查询中的第一个 subquery依赖于外部的子查询

derived: 派生表 select(from子句中的子查询)

table

记录查询引用的表。

type

表连接类型。以下列出了各种不同类型的表连接,依次是从最好的到最差的:

system:表只有一行记录(等于系统表)。这是 const表连接类型的一个特例。

const:表中最多只有一行匹配的记录,它在查询一开始的时候就会被读取出来。由于只有一行记录,在余下的优化程序里该行记录的字段值可以被当作是一个 恒定值。const表查询起来非常快,因为只要读取一次!const 用于在和 primary key 或unique 索引中有固定值比较的情形。下面的几个查询中,tbl_name
就是 c表了:

select * from tbl_name where primary_key=1; select * from tbl_namewhere primary_key_part1=1 and primary_key_part2=2;

eq_ref:从该表中会有一行记录被读取出来以和从前一个表中读取出来的记录做联合。与const类型不同的是,这是最好的连接类型。它用在索引所有部 分都用于做连接并且这个索引是一个primary key 或 unique 类型。eq_ref可以用于在进行"="做比较时检索字段。比较的值可以是固定值或者是表达式,表达示中可以使用表里的字段,它们在读表之前已经准备好
了。以下的几个例子中,mysql使用了eq_ref 连接来处理 ref_table:

select * from ref_table,other_table whereref_table.key_column=other_table.column; select * fromref_table,other_table whereref_table.key_column_part1=other_table.column
andref_table.key_column_part2=1;

ref: 该表中所有符合检索值的记录都会被取出来和从上一个表中取出来的记录作联合。ref用于连接程序使用键的最左前缀或者是该键不是 primary key 或 unique索引(换句话说,就是连接程序无法根据键值只取得一条记录)的情况。当根据键值只查询到少数几条匹配的记录时,这就是一个不错的连接类型。
ref还可以用于检索字段使用 =操作符来比较的时候。以下的几个例子中,mysql将使用 ref 来处理ref_table:

select * from ref_table where key_column=expr; select * fromref_table,other_table whereref_table.key_column=other_table.column; select * fromref_table,other_table
whereref_table.key_column_part1=other_table.column andref_table.key_column_part2=1;

ref_or_null: 这种连接类型类似 ref,不同的是mysql会在检索的时候额外的搜索包含null 值的记录。这种连接类型的优化是从mysql4.1.1开始的,它经常用于子查询。在以下的例子中,mysql使用ref_or_null 类型来处理 ref_table:

select * from ref_table where key_column=expr or key_column is null;

unique_subquery: 这种类型用例如一下形式的 in 子查询来替换 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字段表示使用了哪个索引。key_len字段包括了使用的键的最长部分。这种类型时 ref 字段值是 null。range用于将某个字段和一个定植用以下任何操作符比较时 =, <>, >,>=, <, <=, is null,
<=>, between, 或 in:

select * from tbl_name where key_column = 10; select * fromtbl_name where key_column between 10 and 20; select * from tbl_namewhere key_column in (10,20,30);
select * from tbl_name wherekey_part1= 10 and key_part2 in (10,20,30);

index: 连接类型跟 all 一样,不同的是它只扫描索引树。它通常会比 all快点,因为索引文件通常比数据文件小。mysql在查询的字段知识单独的索引的一部分的情况下使用这种连接类型。

all: 将对该表做全部扫描以和从前一个表中取得的记录作联合。这时候如果第一个表没有被标识为const的话就不大好了,在其他情况下通常是非常糟糕的。正常地,可以通过增加索引使得能从表中更快的取得记录以避免all。

possible_keys

possible_keys字段是指 mysql在搜索表记录时可能使用哪个索引。注意,这个字段完全独立于explain 显示的表顺序。这就意味着 possible_keys里面所包含的索引可能在实际的使用中没用到。如果这个字段的值是null,就表示没有索引被用到。这种情况下,就可以检查 where子句中哪些字段那些字段适合增加索引以提高查询的性能。就这样,创建一下索引,然后再用explain
检查一下。详细的查看章节"14.2.2 alter tablesyntax"。想看表都有什么索引,可以通过 show index from tbl_name来看。

key

key字段显示了mysql实际上要用的索引。当没有任何索引被用到的时候,这个字段的值就是null。想要让mysql强行使用或者忽略在 possible_keys字段中的索引列表,可以在查询语句中使用关键字force index, use index,或 ignore index。如果是 myisam
和 bdb 类型表,可以使用 analyzetable 来帮助分析使用使用哪个索引更好。如果是 myisam类型表,运行命令 myisamchk --analyze也是一样的效果。详细的可以查看章节"14.5.2.1 analyze tablesyntax"和"5.7.2 table maintenance and crash recovery"。

key_len

key_len 字段显示了mysql使用索引的长度。当 key 字段的值为 null时,索引的长度就是 null。注意,key_len的值可以告诉你在联合索引中mysql会真正使用了哪些索引。

ref

ref 字段显示了哪些字段或者常量被用来和 key配合从表中查询记录出来。

rows

rows 字段显示了mysql认为在查询中应该检索的记录数。

extra

本字段显示了查询中mysql的附加信息。以下是这个字段的几个不同值的解释:

distinct:mysql当找到当前记录的匹配联合结果的第一条记录之后,就不再搜索其他记录了。

not exists:mysql在查询时做一个 left join优化时,当它在当前表中找到了和前一条记录符合 left join条件后,就不再搜索更多的记录了。下面是一个这种类型的查询例子:

select * from t1 left join t2 on t1.id=t2.id where t2.id isnull;

假使 t2.id 定义为 not null。这种情况下,mysql将会扫描表 t1并且用 t1.id 的值在 t2 中查找记录。当在 t2中找到一条匹配的记录时,这就意味着 t2.id 肯定不会都是null,就不会再在 t2 中查找相同 id值的其他记录了。也可以这么说,对于 t1 中的每个记录,mysql只需要在t2
中做一次查找,而不管在 t2 中实际有多少匹配的记录。

range checked for each record (index map: #)

mysql没找到合适的可用的索引。取代的办法是,对于前一个表的每一个行连接,它会做一个检验以决定该使用哪个索引(如果有的话),并且使用这个索引来从表里取得记录。这个过程不会很快,但总比没有任何索引时做表连接来得快。

using filesort: mysql需要额外的做一遍从而以排好的顺序取得记录。排序程序根据连接的类型遍历所有的记录,并且将所有符合 where条件的记录的要排序的键和指向记录的指针存储起来。这些键已经排完序了,对应的记录也会按照排好的顺序取出来。详情请看"7.2.9how mysql optimizes
order by"。

using index

字段的信息直接从索引树中的信息取得,而不再去扫描实际的记录。这种策略用于查询时的字段是一个独立索引的一部分。

using temporary: mysql需要创建临时表存储结果以完成查询。这种情况通常发生在查询时包含了groupby 和 order by 子句,它以不同的方式列出了各个字段。

using where

where子句将用来限制哪些记录匹配了下一个表或者发送给客户端。除非你特别地想要取得或者检查表种的所有记录,否则的话当查询的extra 字段值不是 using where 并且表连接类型是 all 或 index时可能表示有问题。

如果你想要让查询尽可能的快,那么就应该注意 extra 字段的值为usingfilesort 和 using temporary 的情况。

你可以通过 explain 的结果中 rows字段的值的乘积大概地知道本次连接表现如何。它可以粗略地告诉我们mysql在查询过程中会查询多少条记录。如果是使用系统变量 max_join_size 来取得查询结果,这个乘积还可以用来确定会执行哪些多表select 语句。

下面的例子展示了如何通过 explain提供的信息来较大程度地优化多表联合查询的性能。

假设有下面的 select 语句,正打算用 explain 来检测:

explain select tt.ticketnumber, tt.timein, tt.projectreference,tt.estimatedshipdate, tt.actualshipdate, tt.clientid,tt.servicecodes, tt.repetitiveid,
tt.currentprocess,tt.currentdppers tt.recordvolume, tt.dpprinted, et.country,et_1.country, do.custname from tt, et, et as et_1, do wherett.submittime is null and tt.actualpc = et.employid andtt.assignedpc = et_1.employid and tt.clientid = do.custnmbr;

在这个例子中,先做以下假设:

要比较的字段定义如下:

table column columntype

tt actualpc char(10)

tt assignedpc char(10)

tt clientid char(10)

et employid char(15)

do custnmbr char(15)

数据表的索引如下:

table index

tt actualpc

tt assignedpc

tt clientid

et employid (primary key)

do custnmbr (primary key)

tt.actualpc 的值是不均匀分布的。

在任何优化措施未采取之前,经过 explain分析的结果显示如下:

table type possible_keys key key_len ref rows extra

et all primarynull null null 74

do all primary null null null 2135

et_1 allprimary null null null 74

tt all assignedpc, null null null 3872 clientid, actualpc range checked for each record (key map: 35)

由于字段 type 的对于每个表值都是all,这个结果意味着mysql对所有的表做一个迪卡尔积;这就是说,每条记录的组合。这将需要花很长的时间,因为需要扫描每个表总 记录数乘积的总和。在这情况下,它的积是74 * 2135 * 74 * 3872 = 45,268,558,720条记录。如果数据表更大的话,你可以想象一下需要多长的时间。

在这里有个问题是当字段定义一样的时候,mysql就可以在这些字段上更快的是用索引(对isam类型的表来说,除非字段定义完全一样,否则不会使用索 引)。在这个前提下,varchar和 char是一样的除非它们定义的长度不一致。由于 tt.actualpc 定义为char(10),et.employid
定义为 char(15),二者长度不一致。

为了解决这个问题,需要用 alter table 来加大 actualpc的长度从10到15个字符:

mysql> alter table tt modify actualpc varchar(15);

现在 tt.actualpc 和 et.employid 都是 varchar(15)

了。再来执行一次 explain 语句看看结果:

table type possible_keys key key_len ref rows extra

tt allassignedpc, null null null 3872 using clientid, where actualpc

do all primary null null null 2135 range checked for each record (keymap: 1)

et_1 all primary null null null 74 range checked for eachrecord (key map: 1) et eq_ref primary primary 15 tt.actualpc 1

这还不够,它还可以做的更好:现在 rows值乘积已经少了74倍。这次查询需要用2秒钟。

第二个改变是消除在比较 tt.assignedpc = et_1.employid 和 tt.clientid= do.custnmbr 中字段的长度不一致问题:

mysql> alter table tt modify assignedpc varchar(15), ->modify clientid varchar(15);

现在 explain 的结果如下:

table type possible_keys key key_len ref rows extra

et all primary null null null 74

tt ref assignedpc, actualpc 15 et.employid 52 using clientid, where actualpc

et_1 eq_ref primary primary 15 tt.assignedpc 1

do eq_ref primary primary 15 tt.clientid 1

这看起来已经是能做的最好的结果了。

遗留下来的问题是,mysql默认地认为字段 tt.actualpc的值是均匀分布的,然而表 tt并非如此。幸好,我们可以很方便的让mysql分析索引的分布:

mysql> analyze table tt;

到此为止,表连接已经优化的很完美了,explain 的结果如下:

table type possible_keys key key_len ref rows extra

tt all assignedpc null null null 3872 using clientid, where actualpc

et eq_ref primary primary 15 tt.actualpc 1

et_1 eq_ref primary primary 15 tt.assignedpc 1

do eq_ref primary primary 15 tt.clientid 1

请注意,explain 结果中的 rows字段的值也是mysql的连接优化程序大致猜测的,请检查这个值跟真实值是否基本一致。如果不是,可以通过在select 语句中使用 straight_join 来取得更好的性能,同时可以试着在from分句中用不同的次序列出各个表。

补全:

explain主要用于sql语句中的select查询,可以显示的查看该sql语句索引的命中情况,从而更好的利用索引、优化查询效率。

Explain语法如下:explain [extended] select ...

其中extended是选用的,如果使用的extended,那么explain之后就可以使用show warnings查看相应的优化信息,也就是mysql内部实际执行的query。
列名
描述
说明
相关链接
id
若没有子查询和联合查询,id则都是1。
Mysql会按照id从大到小的顺序执行query,在id相同的情况下,则从上到下执行。
select_type
select类型。
常见类型
table
输出的行所引用的表。
有时看到的是<derivedN>,其中N对应的是id列的值。
type
Mysql的存取方法,连接访问类型。
常见类型
possible_keys
在查询过程中可能用到的索引。
在优化初期创建该列,但在以后的优化过程中会根据实际情况进行选择,所以在该列列出的索引在后续过程中可能没用。该列为NULL意味着没有相关索引,可以根据实际情况看是否需要加索引。
key
访问过程中实际用到的索引。
有可能不会出现在possible_keys中(这时可能用的是覆盖索引,即使query中没有where)。possible_keys揭示哪个索引更有效,key是优化器决定哪个索引可能最小化查询成本,查询成本基于系统开销等总和因素,有可能是“执行时间”矛盾。如果强制mysql使用或者忽略possible_keys中的索引,需要在query中使用FORCE INDEX、USE INDEX或者IGNORE INDEX。
key_len
显示使用索引的字节数。
由根据表结构计算得出,而不是实际数据的字节数。如ColumnA(char(3)) ColumnB(int(11)),在utf-8的字符集下,key_len=3*3+4=13。计算该值时需要考虑字符列对应的字符集,不同字符集对应不同的字节数。
mysql5.1.5下latin1、utf8、gbk字符数、字节数、汉字的对应关系
ref
显示了哪些字段或者常量被用来和
key
配合从表中查询记录出来。显示那些在index查询中被当作值使用的在其他表里的字段或者constants。
rows
估计为返回结果集而需要扫描的行。
不是最终结果集的函数,把所有的rows乘起来可估算出整个query需要检查的行数。有limit时会不准确。(为毛?)
Extra
mysql查询的附加信息。
常见信息
select类型:

simple:query中不包含子查询或联合查询。

primary:包含子查询或联合查询的query中,最外层的select查询。

subquery:子查询在select的目标里,不在from中,子查询的第一个select。

例如:EXPLAIN SELECT (SELECT actor_id FROM actor) FROM film_actor



dependent subquery:子查询内层的第一个select,依赖于外部查询的结果集。

例如:EXPLAIN SELECT * FROM actor WHERE actor_id IN (SELECT actor_id FROM film_actor)



EXPLAIN SELECT * FROM actor WHERE actor_id IN (SELECT actor_id FROM film_actor WHERE actor_id=1)



EXPLAIN SELECT * FROM actor WHERE actor_id = (SELECT actor_id FROM film_actor WHERE actor_id=1)



uncacheable subquery:表示子查询,但返回结果不能被cache,必须依据外层查询重新计算。(在什么情况下会出现这个?)

derived:子查询在from子句中,执行查询的时候会把子查询的结果集放到临时表(衍生表)。

例如:EXPLAIN SELECT * FROM (SELECT * FROM actor) AS a。此时table列会显示<derivedN>,其中N对应id列的值。



union:在联合查询中第二个及其以后的select对应的类型。

例如:EXPLAIN SELECT * FROM film_actor UNION ALL SELECT * FROM actor



如果union包含在一个from子查询里面,则from子查询中的第一个select标记为derived。

例如:EXPLAIN SELECT * FROM ( SELECT * FROM film_actor UNION ALL SELECT * FROM actor) a



union result:从union临时表获取结果集合。例如上面两个查询结果集中的最后一行。<union1,2,...>其中1,2,...所标识的id列表代表id列,当id列表长度超过20个之后就会省略后面的<union1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,...>。例子如上图。

dependent union:子查询中的union,且为union中第二个select开始的后面所有select,同样依赖于外部查询的结果集。

例如:EXPLAIN SELECT * FROM actor WHERE actor_id IN (SELECT actor_id FROM film_actor UNION ALL SELECT actor_id FROM film_actor)



uncacheable union:表示union第二个或以后的select,但结果不能被cache,必须依据外层查询重新计算。(在什么情况下会出现)

按照效率从高到低给出几种常见的type类型:

NULL:mysql在优化过程中分解query,执行时甚至不用再访问表数据或者索引,比如id=-1。

例如:EXPLAIN SELECT * FROM actor WHERE actor_id = -1


system:查询的表仅有一行。这是const联接类型的一个特例。(在没有任何索引的情况下,只有一条数据,MyISAM会显示system,InnoDB会显示ALL)

const:最多会有一条记录匹配。因为仅有一行,在这行的列值可被优化器剩余部分认为是常数。const表很快,因为它们只读取一次。发生在有一个unique key或者主键,并且where子句给它设定了一个比较值。

例如:EXPLAIN SELECT * FROM actor WHERE actor_id = 1(其中actor_id是主键)



eq_ref:使用这种索引查找,最多返回一条符合条件的记录。会在使用主键或者唯一性索引访问数据时看到,除了const类型这可能是最好的联接类型。

例如:EXPLAIN SELECT * FROM actor, actorsex WHERE actor.actor_id = actorsex.actor_id(其中actor_id是actor、actorsex的主键,且actorsex中只有一条记录,如果多于一条记录就不是eq_ref)



ref:这是一种索引访问。只有当使用一个非唯一性索引或者唯一性索引的非唯一性前缀(换句话说,就是无法根据该值只取得一条记录)时才会发生,将索引和某个值相比较,这个值可能是一个常数,也可能是来自前一个表里的多表查询的结果值。如果使用的键仅仅匹配少量行,该联接类型是不错的。

例如:EXPLAIN SELECT * FROM film_actor,actor WHERE film_actor.actor_id=actor.actor_id AND film_actor.actor_id=1



ref_or_null:类似ref。不同的是Mysql会在检索的时候额外的搜索包含 NULL 值的记录,他意味着mysql必须进行二次查找,在初次查找的结果中找出NULL条目。

index_merge:查询中使用两个或多个索引,然后对索引结果进行合并。在这种情况下,key列包含所有使用的索引,key_len包含这些索引的最长的关键元素。

select * from test where column1 = 1 or column2 = 2(没试出来!555555)

unique_subquery:用来优化有子查询的in,并且该子查询是通过一个unique key选择的。子查询返回的字段组合是主键或者唯一索引。

例如:EXPLAIN SELECT * FROM actor WHERE actor_id IN (SELECT actor_id FROM actor)



index_subquery:该联接类型类似于unique_subquery,子查询中的返回结果字段组合是一个索引或索引组合,但不是一个主键或者唯一索引。

例如:EXPLAIN SELECT * FROM film_actor WHERE film_id IN (SELECT film_id FROM film_actor)


range:在一定范围内扫描索引。如where中带有between或者>,此时ref列为NULL。当使用=、<>、>、>=、<、<=、IS
NULL、<=>、BETWEEN或者IN操作符,用常量比较关键字列时,可以使用range。

index:按索引次序扫描数据。因为按照索引扫描所以会避免排序,但也会扫描整表数据,若随机读取开销会更大。如果extra列显示using index,说明使用的是覆盖索引(覆盖索引:包含所有满足查询需要的数据列的索引)。对于InnoDB表特别有用,此时只访问索引数据即可,不用再根据主键信息获取原数据行,避免了二次查询,而MyISAM表优化效果相对InnoDB来说没有那么的明显。

all:按行扫描全表数据,除非查询中有limit或者extra列显示使用了distinct或notexists等限定词。

Extra信息 :

distinct:当mysql找到第一条匹配的结果值时,就停止该值的查询,然后继续该列其他值的查询。

not exists:在左连接中,优化器可以通过改变原有的查询组合而使用的优化方法。当发现一个匹配的行之后,不再为前面的行继续检索,可以部分减少数据访问的次数。例如,表t1、t2,其中t2.id为not null,对于SELECT * FROM t1 LEFT JOIN t2 ON t1.id=t2.id WHERE t2.id IS NULL;由于 t2.id非空,所以只可能是t1中有,而t2中没有,所以其结果相当于求差。left join原本是要两边join,现在Mysql优化只需要依照 t1.id在t2中找到一次t2.id即可跳出。

const row not found:涉及到的表为空表,里面没有数据。

Full scan on NULL key:是优化器对子查询的一种优化方式,无法通过索引访问NULL值的时候会做此优化。

Impossible Having:Having子句总是false而不能选择任何列。例如having 1=0

Impossible WHERE:Where子句总是false而不能选择任何列。例如where 1=0

Impossible WHERE noticed after reading const tables:mysql通过读取“const/system tables”,发现Where子句为false。也就是说:在where子句中false条件对应的表应该是const/system tables。这个并不是mysql通过统计信息做出的,而是真的去实际访问一遍数据后才得出的结论。当对某个表指定了主键或者非空唯一索引上的等值条件,一个query最多只可能命中一个结果,mysql在explain之前会优先根据这一条件查找对应记录,并用记录的实际值替换query中所有用到来自该表属性的地方。

例如:select * from a,b where a.id = 1 and b.name = a.name

执行过程如下:先根据a.id = 1找到一条记录(1, 'name1'),然后将b.name换成'name1',然后通过a.name = 'name1'查找,发现没有命中记录,最终返回“Impossible WHERE noticed after reading const tables”。

No matching min/max row:没有行满足如下的查询条件。

例如:EXPLAIN SELECT MIN(actor_id) FROM actor WHERE actor_id > 3(只有两条记录)

actor_id为唯一性索引时,会显示“No matching min/max row”,否则会显示“using where”。

no matching row in const table:对一个有join的查询,包含一个空表或者没有数据满足一个唯一索引条件。

No tables used:查询没有From子句,或者有一个From Dual(dual:虚拟表,是为了满足select...from...习惯)子句。

例如:EXPLAIN SELECT VERSION()

Range checked for each record (index map: N):Mysql发现没有好的index,但发现如果进一步获取下一张join表的列的值后,某些index可以通过range等使用。Mysql没找到合适的可用的索引。取代的办法是,对于前一个表的每一个行连接,它会做一个检验以决定该使用哪个索引(如果有的话),并且使用这个索引来从表里取得记录。这个过程不会很快,但总比没有任何索引时做表连接来得快。

Select tables optimized away:当我们使用某些聚合函数来访问存在索引的某个字段时,优化器会通过索引直接一次定位到所需要的数据行完成整个查询。在使用某些聚合函数如min, max的query,直接访问存储结构(B树或者B+树)的最左侧叶子节点或者最右侧叶子节点即可,这些可以通过index解决。Select count(*) from table(不包含where等子句),MyISAM保存了记录的总数,可以直接返回结果,而Innodb需要全表扫描。Query中不能有group by操作。

unique row not found:对于SELECT … FROM tbl_name,没有行满足unique index或者primary key。从表中查询id不存在的一个值会显示Impossible WHERE noticed after reading const tables。

Using filesort:指Mysql将用外部排序而不是按照index顺序排列结果。数据较少时从内存排序,否则从磁盘排序。Explain不会显示的告诉客户端用哪种排序。

Using index:表示Mysql使用覆盖索引避免全表扫描,不需要再到表中进行二次查找数据。注意不要和type中的index类型混淆。

Using index for group-by:类似Using index,所需数据只需要读取索引,当query中有group by或distinct子句时,如果分组字段也在索引中,extra就会显示该值。

Using temporary:Mysql将创建一个临时表来容纳中间结果。在group by和order by的时,如果有必要的话。例如group by一个非键列,优化器会创建一个临时表,有个按照group by条件构建的unique key,然后对于每条查询结果(忽略group by),尝试insert到临时表中,如果由于unique key导致insert失败,则已有的记录就相应的updated。例如,name上没有索引,SELECT name,COUNT(*) FROM product GROUP BY
name,为了排序,Mysql就需要创建临时表。此时一般还会显示using filesort。

Using where:表示Mysql将对storage engine提取的结果进行过滤。例如,price没有index,SELECT * FROM product WHERE price=1300.00。有许多where的条件由于包含了index中的列,在查找的时候就可以过滤,所以不是所有带where子句的查询会显示Using where。

Using join buffer:5.1.18版本以后才有的值。join的返回列可以从buffer中获取,与当前表join。

例如:explain select * from t1,t2 where t1.col < 10 and t2.col < 10

Scanned N databases:指在处理information_schema查询时,有多少目录需要扫描。

例如:EXPLAIN SELECT TABLE_NAME, ROW_FORMAT FROM INFORMATION_SCHEMA.TABLES

网上说这个查询会显示Scanned all databases,我试了下extra列是空。

Skip_open_table, Open_frm_only, Open_trigger_only, Open_full_table:指示从information_schema查询信息时有关文件开启的优化。 Skip_open_table:表信息已经获得,不需要打开。 Open_frm_only:只打开.frm文件。 Open_trigger_only:只打开.trg文件。 Open_full_table:没有优化。.frm,.myd和.myi文件都打开。

Using sort_union(…), Using union(…), Using intersect(…):都出现在index_merge读取类型中。 Using sort_union:用两个或者两个以上的key提取数据,但优化器无法确保每个key会提取到一个自然排好序的结果,所以为了排除多余的数据,需要额外的处理。例如,customer的state,(lname,fname)是key,但lname不是key,SELECT COUNT(*) FROM customer WHERE (lname = ‘Jones')
OR (state = ‘UT'),由于lname上面没有key,所以使用(lname,fname),使得结果可能不按照顺序,优化器需要额外的一些工作。 Using union:用两个或者两个以上的key提取数据,分别取得结果是已排序,通过合并就可以获得正确结果。例如,customer中的state和(lname,fname)是key,SELECT COUNT(state) FROM customer WHERE (lname = ‘Jones' AND fname='John') OR (state =
‘UT')。 Using intersect:用两个或者两个以上的key提取数据,分别取得结果是已排序,通过求交就可以获得正确结果。例如,customer中的state和(lname,fname)是key,SELECT COUNT(state) FROM customer WHERE (lname = ‘Jones' AND fname='John') AND (state = ‘UT')。

Using where with pushed condition:仅用在ndb上。Mysql Cluster用Condition Pushdown优化改善非索引字段和常量之间的直接比较。condition被pushed down到cluster的数据节点,并在所有数据节点同时估算,把不合条件的列剔除避免网络传输。

mysql5.1.5下latin1、utf8、gbk字符数、字节数、汉字的对应关系:

latin1:

1character=1byte, 1汉字=2character 一个字段定义成varchar(200),可以存储100个汉字或者200个字符,占用200个字节。尤其是当字段内容是字母和汉字组成时,尽量假设字段内容都是由汉字组成,据此来设置字段长度。

utf8:

1character=3bytes, 1汉字=1character一个字段定义成 varchar(200),则它可以存储200个汉字或者200个字母,占用600个字节。

gbk:

1character=2bytes,1汉字=1character一个字段定义成 varchar(200),则它可以存储200个汉字或者200个字母,占用400个字节。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: