技术开发 频道

浅谈MySQL数据库优化

3 SELECT优化

3.1 MYSQL数据库的SQL执行计划解释器

EXPLAIN tbl_name

或者如下:

EXPLAIN [EXTENDED] SELECT select_options

EXPLAIN tbl_name是DESCRIBE tbl_name或SHOW COLUMNS FROM tbl_name的一个同义词。
mysql> explain a; +-------+---------+------+-----+---------+-------+ | Field | Type | Null | Key | Default | Extra | +-------+---------+------+-----+---------+-------+ | id | int(11) | YES | UNI | NULL | | +-------+---------+------+-----+---------+-------+ 1 row in set (0.02 sec) mysql> explain t; +-------+-------------+------+-----+---------+-------+ | Field | Type | Null | Key | Default | Extra | +-------+-------------+------+-----+---------+-------+ | id | int(11) | NO | PRI | 0 | | | MC | varchar(60) | YES | | NULL | | +-------+-------------+------+-----+---------+-------+ 2 rows in set (0.00 sec) mysql> select * from t; +-------+------+ | id | MC | +-------+------+ | 1 | MC | | 2 | NULL | | 3 | NULL | | 4 | NULL | | 5 | NULL | | 6 | NULL | | 7 | NULL | | 8 | NULL | | 9 | NULL | | 10000 | MC | +-------+------+ 10 rows in set (0.00 sec) mysql> select * from a; +------+ | id | +------+ | NULL | | 1 | | 2 | +------+ 3 rows in set (0.00 sec) mysql> explain select * from A where id in (select id from T)\G *************************** 1. row *************************** id: 1 select_type: PRIMARY table: A type: index possible_keys: NULL key: idx_a key_len: 5 ref: NULL rows: 3 Extra: Using where; Using index *************************** 2. row *************************** id: 2 select_type: DEPENDENT SUBQUERY table: T type: unique_subquery possible_keys: PRIMARY key: PRIMARY key_len: 4 ref: func rows: 1 Extra: Using index 2 rows in set (0.02 sec)
unique_subquery是一个索引查找函数,可以完全替换子查询,效率更高。

index_subquery
该联接类型类似于unique_subquery。可以替换IN子查询,但只适合下列形式的子查询中的非唯一索引:
mysql> explain select * from test where id in (select id from a)\G *************************** 1. row *************************** id: 1 select_type: PRIMARY table: test type: ALL possible_keys: NULL key: NULL key_len: NULL ref: NULL rows: 1534755 Extra: Using where *************************** 2. row *************************** id: 2 select_type: DEPENDENT SUBQUERY table: a type: index_subquery possible_keys: idx_a key: idx_a key_len: 5 ref: func rows: 1 Extra: Using index 2 rows in set (0.00 sec)

range
索引范围扫描,只检索给定范围的行,使用一个索引来选择行。key列显示使用了哪个索引。key_len包含所使用索引的最长关键元素。在该类型中ref列为NULL。当使用=、<>、>、>=、<、<=、IS NULL、<=>、BETWEEN或者IN操作符,用常量比较关键字列时,可以使用range:
mysql> explain select * from t where id=1 or id=10000 or id=3\G; *************************** 1. row *************************** id: 1 select_type: SIMPLE table: t type: range possible_keys: PRIMARY key: PRIMARY key_len: 4 ref: NULL rows: 3 Extra: Using where 1 row in set (0.00 sec) mysql> explain select * from t where id<=3\G; *************************** 1. row *************************** id: 1 select_type: SIMPLE table: t type: range possible_keys: PRIMARY key: PRIMARY key_len: 4 ref: NULL rows: 4 Extra: Using where 1 row in set (0.00 sec) ERROR: No query specified

index
索引全扫描,该联接类型与ALL相同,除了只有索引树被扫描。这通常比ALL快,因为索引文件通常比数据文件小。当查询只使用作为单索引一部分的列时,MySQL可以使用该联接类型。
mysql> explain select * from t\G; *************************** 1. row *************************** id: 1 select_type: SIMPLE table: t type: index possible_keys: NULL key: idx_t_mc key_len: 63 ref: NULL rows: 10 Extra: Using index 1 row in set (0.00 sec) ERROR: No query specified

ALL
全表扫描,对于每个来自于先前的表的行组合,进行完整的表扫描。如果表是第一个没标记cnst的表,这通常不好,并且通常在它情况下很差。通常可以增加更多的索引而不要使用ALL,使得行能基于前面的表中的常数值或列值被检索出。

mysql> explain select * from test\G; *************************** 1. row *************************** id: 1 select_type: SIMPLE table: test type: ALL possible_keys: NULL key: NULL key_len: NULL ref: NULL rows: 1534755 Extra: 1 row in set (0.06 sec) ERROR: No query specified

pssible_keys
pssible_keys列指出MySQL能使用哪个索引在该表中找到行。注意,该列完全独立于EXPLAIN输出所示的表的次序。这意味着在pssible_keys中的某些键实际上不能按生成的表次序使用。如果该列是NULL,则没有相关的索引。在这种情况下,可以通过检查WHERE子句看是否它引用某些列或适合索引的列来提高你的查询性能。如果是这样,创造一个适当的索引并且再次用EXPLAIN检查查询。

为了看清一张表有什么索引,使用SHOW INDEX FROM tbl_name。
mysql> show index from t; +-------+------------+----------+--------------+-------------+-----------+------ -------+----------+--------+------+------------+---------+ | Table | Non_unique | Key_name | Seq_in_index | Column_name | Collation | Cardi nality | Sub_part | Packed | Null | Index_type | Comment | +-------+------------+----------+--------------+-------------+-----------+------ -------+----------+--------+------+------------+---------+ | t | 0 | PRIMARY | 1 | id | A | 2 | NULL | NULL | | BTREE | | | t | 1 | idx_t_mc | 1 | MC | A | 2 | NULL | NULL | YES | BTREE | | +-------+------------+----------+--------------+-------------+-----------+------ -------+----------+--------+------+------------+---------+ 2 rows in set (0.08 sec)
key
key列显示MySQL实际决定使用的键(索引)。如果没有选择索引,键是NULL。要想强制MySQL使用或忽视pssible_keys列中的索引,在查询中使用FRCE INDEX、USE INDEX或者IGNRE INDEX。对于MyISAM和BDB表,运行ANALYZE TABLE可以帮助优化器选择更好的索引。对于MyISAM表,可以使用myisamchk --analyze。
mysql> explain select * from t where id=1 or mc='1'\G *************************** 1. row *************************** id: 1 select_type: SIMPLE table: t type: index possible_keys: PRIMARY,idx_t_mc key: idx_t_mc key_len: 63 ref: NULL rows: 10 Extra: Using where; Using index 1 row in set (0.00 sec) mysql> explain select * from t ignore index(idx_t_mc) where id=1 or mc='1'\G *************************** 1. row *************************** id: 1 select_type: SIMPLE table: t type: ALL possible_keys: PRIMARY key: NULL key_len: NULL ref: NULL rows: 10 Extra: Using where 1 row in set (0.00 sec)
key_len
key_len列显示MySQL决定使用的键长度。如果键是NULL,则长度为NULL。注意通过key_len值我们可以确定MySQL将实际使用一个多部关键字的几个部分。

ref
ref列显示使用哪个列或常数与key一起从表中选择行。

rows
rows列显示MySQL认为它执行查询时必须检查的行数。

Extra
该列包含MySQL解决查询的详细信息。下面解释了该列可以显示的不同的文本字符串:

Distinct
MySQL发现第1个匹配行后,停止为当前的行组合搜索更多的行。
Not exists
MySQL能够对查询进行LEFT JIN优化,发现1个匹配LEFT JIN标准的行后,不再为前面的的行组合在该表内检查更多的行。

当使用EXTENDED关键字时,EXPLAIN产生附加信息,可以用SHOW WARNINGS浏览。该信息显示优化器限定SELECT语句中的表和列名,重写并且执行优化规则后SELECT语句是什么样子,并且还可能包括优化过程的其它注解。
0
相关文章