A、最先出现的条件一定是过滤和排除掉更多结果的条件;第二出线的次之,一次类推。因此表中不同字段的值的分布对查询速度有很大的影响,而ORDER BY中的条件,只与索引有关,与条件顺序无关。
B、大多数情况下,根据WHERE条件的先后顺序和ORDER BY的排序字段的先后顺序而建立的联合索引,就是这条SQL语句匹配的最优索引结构。
1、EXPLAIN语法(获取SELECT的信息)
EXPLAIN tbl_name 或 EXPLAIN [EXTENDED] SELCET select_options
在SELECT语句前放入EXPLAIN关键字,数据库将解释他是如何处理SELECT,提供有关表如何连接以及表连接的次序。
id:select查询序列号
select_type:select类型:1、SIMPLE--简单SELECT(不包含子查询和union)
2、PRIMARY--最外面的SELECT
3、UNION(联合)--UNION中的第二个或后面的SELECT语句
4、DEPENDENT(独立的) UNION--UNION中的第二个或者后面的SELECT语句,取决于外边的查询
5、UNION RESULT--UNION的查询结果
6、SUBQUERY--子查询中的第一个SELECT
7、DEPENDENT SUBQUERY--子查询中的第一个查询,取决于外边的SELCET
8、 DERIVED(派生)--导出表的SELECT(FROM子句的子查询)
table:输出行所引用的表
type:连接类型,按照最佳类型到最坏类型排序:
1、system--表仅有一行(=系统表),const连接类型的一个特例,例子参上
2、const--表最多有一个匹配行,只读取一次,速度很快,const用于用常数值比较PRIMARY KEY或UNIQUE索引的所有部分时,eg:
1、SELECT * from tbl_name WHERE primary_key=1;
2、SELECT * from tbl_name WHERE primary_key_part1=1和 primary_key_part2=2;
3、eq_ref--除了const外最好的连接类型,它用在一个索引的所有部分被联接使用并且
索引是UNIQUE或PRIMARY KEY。
eq_ref可以用于使用= 操作符比较的
带索引的列。比较值可以为常量或一个使用在该表前面所读取的表的列的表达式。eg:
1、SELECT * FROM ref_table,other_table WHERE ref_table.key_column=other_table.column;
2、SELECT * FROM ref_table,other_table WHERE ref_table.key_column_part1=other_table.column AND ref_table.key_column_part2=1;
4、ref-- 对于每个来自于前面的表的行组合,所有有匹配索引值的行将从这张表中读取。如果联接只使用键的最左边的前缀,或如果键不是UNIQUE或PRIMARY KEY(换句话说,如果联接不能基于关键字选择单个行的话),则使用ref。如果使用的键仅仅匹配少量行,该联接类型是不错的。ref可以用于使用=或<=>操作符的
带索引的列。
1、SELECT * FROM ref_table WHERE key_column=expr;
2、SELECT * FROM ref_table,other_table WHERE ref_table.key_column=other_table.column;
3、SELECT * FROM ref_table,other_table WHERE ref_table.key_column_part1=other_table.column AND ref_table.key_column_part2=1;
5、ref or null--该联接类型如同ref,但是添加了MySQL可以专门搜索包含NULL值的行。在解决子查询中经常使用该联接类型的优化。
SELECT * FROM ref_table WHERE key_column=expr OR key_column IS NULL;
6、index-merge--该联接类型表示使用了索引合并优化方法。在这种情况下,key列包含了使用的索引的清单,key_len包含了使用的索引的最长的关键元素。
8、unique_subquery
9、index_subquery
10、rang--只检索给定范围的行,使用一个索引来选择行。key列显示使用了哪个索引。key_len包含所使用索引的最长关键元素。在该类型中ref列为NULL。
当使用=、<>、>、>=、<、<=、IS NULL、<=>、BETWEEN或者IN操作符,用常量比较关键字列时,可以使用range
11、index--该联接类型与ALL相同,除了只有索引树被扫描。这通常比ALL快,因为索引文件通常比数据文件小。当查询只使用作为单索引一部分的列时,MySQL可以使用该联接类型。
12、ALL--对于每个来自于先前的表的行组合,进行完整的表扫描。如果表是第一个没标记const的表,这通常不好,并且通常在它情况下很差。通常可以增加更多的索引而不要使用ALL,使得行能基于前面的表中的常数值或列值被检索出。
possible_key:possible_keys列指出mysql能使用哪个索引在该表中找到行。注意,该列完全独立于EXPLAIN输出所示的表的次序。这意味着在possible_keys中的某些键实际上不能按生成的表次序使用。如果该列是NULL,则没有相关的索引。在这种情况下,可以通过检查WHERE子句看是否它引用某些列或适合索引的列来提高你的查询性能。如果是这样,创造一个适当的索引并且再次用EXPLAIN检查查询.
key:key列显示mysql实际决定使用的键(索引)。如果没有选择索引,键是NULL。要想强制MySQL使用或忽视possible_keys列中的索引,在查询中使用FORCE INDEX、USE INDEX或者IGNORE INDEX。
key_len:key_len列显示
MySQL决定使用的键长度。如果键是NULL,则长度为NULL。注意通过key_len值我们可以确定MySQL将实际使用一个多部关键字的几个部分。
ref:ref列显示使用哪个列或常数与key一起从表中选择行。
rows:rows列表示mysql要遍历多少数据才能找到,在innodb上不准确。
Extra:该列包含MySQL解决查询的详细信息。下面解释了该列可以显示的不同的文本字符串:
1、Distinct(清晰)--MySQL发现第1个匹配行后,停止为当前的行组合搜索更多的行。
2、Not exists--MySQL能够对查询进行LEFT JOIN优化,发现1个匹配LEFT JOIN标准的行后,不再为前面的的行组合在该表内检查更多的行。
SELECT * FROM t1 LEFT JOIN t2 ON t1.id=t2.id WHERE t2.id IS NULL;
假定t2.id定义为NOT NULL。在这种情况下,MySQL使用t1.id的值扫描t1并查找t2中的行。如果MySQL在t2中发现一个匹配的行,它知道t2.id绝不会为NULL,并且不再扫描t2内有相同的id值的行。换句话说,对于t1的每个行,MySQL只需要在t2中查找一次,无论t2内实际有多少匹配的行。
3、range checked for each record (index map: #):没有好的索引
4、Using filesort:用到额外排序(当使用order by排序而没有用到索引时,就会出现该语句)
5、Using index:只用到索引,可以避免访问表
6、Using temporay:用到临时表
7、Using where:使用到where来过滤数据