执行 SQL query 时,MySQL 会为 SQL 的执行尝试一个最优的执行计划。通过在查询命令前加 EXPLAIN 就可以看到 MySQL 的执行计划。EXPLAIN 是了解和优化 MySQL 查询的利器之一。
EXPLAIN SELECT * FROM users\G
********************** 1. row **********************
id: 1
select_type: SIMPLE
table: users
type: ALL
possible_keys: NULL
key: NULL
key_len: NULL
ref: NULL
rows: 4
Extra:
1 row in set (0.00 sec)
上面 10 个返回值的意思分别是:
id 每个 SELECT 查询标识select_type SELECT 的类型,可能有的值:
SIMPLE 只是简单查询,没有子查询或 UNIONPRIMARY 最外层的 SELECT 有 JOINDERIVED SELECT 是 FROM 后的一个子查询SUBQUERY 子查询中的第一个 SELECTDEPENDENT SUBQUERY 一个子查询,依赖外层的查询UNCACHEABLE SUBQUERY 一个不能被缓存的子查询UNION SELECT 是一个 UNION 第二个以后的查询DEPENDENT UNION UNION 第二个之后个 SELECT 依赖于外层的查询UNION RESULT SELECT 是一个 UNION 的结果table 查询到的行所在的表type MySQL 怎样 join 各表的。这是输出结果中最重要的结果之一。它可以看出是否有缺失的索引或者查询是否需要重写。
system 表只有 0 行或 1 行。const 表中只有 1 行匹配并且被索引。这是 join 中最快的类型,因为表只被读了一次并且列的值在 join 其它表的时候是一个常量。eq_ref 索引所有的部分都被使用,并且索引是主键或者不为空的唯一索引。这是第二好的 join 类型。ref 非唯一性索引扫描,返回匹配某个单独值的所有行。常见于使用非唯一索引即唯一索引的非唯一前缀进行的查找。full_text join 使用了表的 FULLTEXT 索引ref_or_null 这个和 ref 一样,但是它的列中包含 nullindex_merge join 使用了一系列的索引来生成结果。EXPLAIN 的 key 输出项将标明哪些索引被用到uniq_subquery 一个 IN 的子查询只返回了一个结果并且使用了主键index_subquery 和 uniq_subquery 一样,不过返回多于一条结果range 索引被用来在某一指定范围内查找,特别是索引的列作为条件来和常数做比较,像 BETWEEN, IN 或 <, > 等index 整个索引都被扫描了一遍all 整个表被扫了一遍才找出 join 后匹配的结果。这是 join 最坏的结果,一般说明表缺少合适的索引。possible_keys 显示可以被 MySQL 利用的索引来查找结果,但是它们可能真正被使用了,也可能没被用到。这个结果如果是 NULL,通常可以帮助优化查询,它说明没有找到相关的索引。key 指出真正被 MySQL 用到的索引。这里可能列出没有列在 possible_keys 结果项中的索引。MySQL 通常会找一个最优的索引来进行查找。当 join 很多表时,它可能会找到一些没有列在 possible_key 中的,但是更优化的索引。key_len 查询优化器1所选择的索引的长度。比如,key_len 为 4 则说明它需要在内存中保存 4 个字符。ref 哪些列或常数与列在 key 项中的索引进行比较,并从表中选出结果rows 查出最终结果一共检查了多少记录。这是另一个非常值得注意用来优化查询的指标,特别对于 join 和子查询的情况。Extra 包含了执行计划的额外信息可以在 EXPLAIN 后加上 EXTENDED, 这会显示执行计划的额外信息。在执行 EXPLAIN 后执行 SHOW WARNINGS 。这个东西可以看到被查询优化器优化后的样子。
EXPLAIN EXTENDED SELECT City.Name FROM City JOIN Country ON (City.CountryCode = Country.Code) WHERE City.CountryCode = 'IND' AND Country.Continent = 'Asia'\G
********************** 1. row **********************
id: 1
select_type: SIMPLE
table: Country
type: const
possible_keys: PRIMARY
key: PRIMARY
key_len: 3
ref: const
rows: 1
filtered: 100.00
Extra:
********************** 2. row **********************
id: 1
select_type: SIMPLE
table: City
type: ALL
possible_keys: NULL
key: NULL
key_len: NULL
ref: NULL
rows: 4079
filtered: 100.00
Extra: Using where
2 rows in set, 1 warning (0.00 sec)
SHOW WARNINGSG
********************** 1. row ********************** Level: Note Code: 1003 Message: select `World`.`City`.`Name` AS `Name` from `World`.`City` join `World`.`Country` where ((`World`.`City`.`CountryCode` = 'IND')) 1 row in set (0.00 sec)
Query Optimizer ↩