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;
select * from ref_table,other_tablewhereref_table.key_column=other_table.column; select *fromref_table,other_tablewhereref_table.key_column_part1=other_table.columnandref_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_tablewhereref_table.key_column_part1=other_table.columnandref_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_namewhere key_column between 10 and 20; select * from tbl_namewherekey_column in (10,20,30); select * from tbl_name wherekey_part1= 10 andkey_part2 in (10,20,30);
index: 连接类型跟 all 一样,不同的是它只扫描索引树。它通常会比 all快点,因为索引文件通常比数据文件小。mysql在查询的字段知识单独的索引的一部分的情况下使用这种连接类型。
possible_keys
possible_keys字段是指 mysql在搜索表记录时可能使用哪个索引。注意,这个字段完全独立于explain 显示的表顺序。这就意味着possible_keys里面所包含的索引可能在实际的使用中没用到。如果这个字段的值是null,就表示没有索引被用到。这种情况下,就可以检查where子句中哪些字段那些字段适合增加索引以提高查询的性能。就这样,创建一下索引,然后再用explain检查一下。详细的查看章节"14.2.2 alter tablesyntax"。想看表都有什么索引,可以通过 show indexfromtbl_name来看。
key
key字段显示了mysql实际上要用的索引。当没有任何索引被用到的时候,这个字段的值就是null。想要让mysql强行使用或者忽略在possible_keys字段中的索引列表,可以在查询语句中使用关键字force index, use index,或 ignoreindex。如果是 myisam 和 bdb 类型表,可以使用 analyzetable 来帮助分析使用使用哪个索引更好。如果是myisam类型表,运行命令 myisamchk --analyze也是一样的效果。详细的可以查看章节"14.5.2.1analyzetablesyntax"和"5.7.2 table maintenance and crash recovery"。
not exists:mysql在查询时做一个 left join优化时,当它在当前表中找到了和前一条记录符合 left join条件后,就不再搜索更多的记录了。下面是一个这种类型的查询例子:
select * from t1 left join t2 on t1.id=t2.id where t2.id isnull;
using filesort: mysql需要额外的做一遍从而以排好的顺序取得记录。排序程序根据连接的类型遍历所有的记录,并且将所有符合where条件的记录的要排序的键和指向记录的指针存储起来。这些键已经排完序了,对应的记录也会按照排好的顺序取出来。详情请看"7.2.9howmysql 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, dowherett.submittime is null and tt.actualpc = et.employidandtt.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)
现在 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