简述
在 MySQL 中,当数据量增长的特别大的时候就需要用到索引来优化 SQL 语句,使用 Explain
来查看 SQL 语句的执行计划,是优化 SQL 最有效地的一种手段。
使用方法
语法:explain + SQL
示例:explain select * from customer
1 | mysql> explain select * from customer; |
参数介绍
id
含义:SELECT 标识符,SQL 执行顺序的标识。
三种情况:
id
相同,执行顺序由上至下。1
2
3
4
5
6
7
8mysql> explain select t2.* from t1,t2,t3 where t1.id = t2.id and t1.id = t3.id and t1.other_column = '';
+----+-------------+-------+--------+---------------+---------+---------+---------------+------+-------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+-------+--------+---------------+---------+---------+---------------+------+-------------+
| 1 | SIMPLE | t1 | ALL | PRIMARY | NULL | NULL | NULL | 5 | Using where |
| 1 | SIMPLE | t2 | eq_ref | PRIMARY | PRIMARY | 4 | test_db.t1.id | 1 | |
| 1 | SIMPLE | t3 | eq_ref | PRIMARY | PRIMARY | 4 | test_db.t1.id | 1 | Using index |
+----+-------------+-------+--------+---------------+---------+---------+---------------+------+-------------+id
不同,如果是子查询,id
的序号会递增,id
值越大优先级越高,越先被执行。1
2
3
4
5
6
7
8mysql> explain select t2.* from t2 where id = (select id from t1 where id = (select t3.id from t3 where t3.other_column = ''));
+----+-------------+-------+-------+---------------+---------+---------+-------+------+-------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+-------+-------+---------------+---------+---------+-------+------+-------------+
| 1 | PRIMARY | t2 | const | PRIMARY | PRIMARY | 4 | const | 1 | |
| 2 | SUBQUERY | t1 | const | PRIMARY | PRIMARY | 4 | | 1 | Using index |
| 3 | SUBQUERY | t3 | ALL | NULL | NULL | NULL | NULL | 5 | Using where |
+----+-------------+-------+-------+---------------+---------+---------+-------+------+-------------+id
有相同也有不同,id
值越大,优先级越高,越先执行;id
相同,则认为是一组,从上往下顺序执行。1
2
3
4
5
6
7
8mysql> explain select t2.* from t2 where id = (select id from t1 where id = (select t3.id from t3 where t3.other_column = ''));
+----+-------------+-------+-------+---------------+---------+---------+-------+------+-------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+-------+-------+---------------+---------+---------+-------+------+-------------+
| 1 | PRIMARY | t2 | const | PRIMARY | PRIMARY | 4 | const | 1 | |
| 2 | SUBQUERY | t1 | const | PRIMARY | PRIMARY | 4 | | 1 | Using index |
| 3 | SUBQUERY | t3 | ALL | NULL | NULL | NULL | NULL | 5 | Using where |
+----+-------------+-------+-------+---------------+---------+---------+-------+------+-------------+
select_type
含义:查询类型,主要用于区别普通查询、联合查询、子查询等复杂查询。
六种类型:
- SIMPLE:简单的
select
查询,查询中不包含子查询或者union
联合查询。 - PRIMARY:查询中若包含任何复杂的子部分,最外层查询则被标记为
PRIMARY
。 - SUBQUERY:在
select
或where
列表中包含了子查询。 - DERIVED:在
from
列表中包含的子查询被标记为DERIVED
(衍生),MySQL 会递归执行这些子查询,把结果放在临时表里。 - UNION:若第二个
select
出现在union
之后,则被标记为union
;若union
包含在from
字句的查询中,外层select
将被标记为DERIVED
。 - UNION RESULT:两种
union
语句的合并。
table
含义:查询涉及的表或者衍生表。
type
含义:显示连接使用的类型。常见的有7种,从最好到最差排序:system > const > eq_ref > ref > range > index > all(全表扫描),一般来说 至少达到 range 级别,最好达到 ref。
七种类型:
system:表只有一行记录,这是
const
类型的特例,只能用于myisam
和memory
表,可以忽略不计。const:表示通过索引一次就找到了,
const
用于primary key
或者unique
索引,因为只匹配一行数据,所以很快,如将主键置于where
列表中,MySQL 就能将该查询转换为一个常量。
1 | mysql> explain select * from (select * from t1 where id =1) d1; |
- eq_ref:唯一性索引扫描,对于每个索引键,表中只有一条记录与之匹配,常见于主键或唯一索引扫描。
1 | mysql> explain select * from t1,t2 where t1.id = t2.id; |
- ref:非唯一索引或者主键扫描,或者使用了最左前缀规则索引的查询,它返回匹配某个单独值的所有行,然而它可能会找到多个符合条件的行,所以它应该属于查找和扫描的混合体。
1 | mysql> create index idx_name on t1(name); |
- range:只检索给定范围的行,使用一个索引来选择行。
key
列显示使用了哪个索引,一般就是在你的where
语句中出现了between
、<>
、in
等查询。这种范围扫描索引比全表扫描要好,因为它只需要开始于索引的某一点,而结束于另一点,不用扫描全部索引。
1 | mysql> explain select * from t1 where id between 2 and 5; |
- index:表示全索引扫描 (full index scan),
index
与all
区别为index
类型只扫描所有的索引不扫描数据,通常比all
快,因为索引文件通常比数据文件小。
1 | mysql> explain select id from t1; |
- all:表示全表扫描,这个类型的查询是性能最差的查询之一。通常来说,查询不应该出现
all
类型的查询, 因为这样的查询在数据量大的情况下,对数据库的性能是巨大的灾难。
1 | mysql> explain select * from t2 where other_column = ''; |
possible_keys
含义:显示可能应用在这张表中的索引。查询涉及到的字段上若存在索引,则该索引将被列出,但不一定被查询实际使用。
key
含义:实际使用的索引。如果为 NULL
,则没有使用索引,key
参数可以作为使用了索引的判断标准。
key_len
含义:使用的索引的长度。key_len
显示的值为索引字段的最大可能长度,并非实际使用长度。在不损失精确性的情况下,长度越短越好。
ref
含义:显示索引的哪一列被使用了,如果可能的话是一个常数,哪些列或常量被用于查找索引列上的值。
rows
含义:根据表统计信息及索引选用情况,大致估算出找到所需的记录所需要读取的行数,当然越小越好。
Tips:explain 结果中,join 的查询代价可以用依次连乘 rows 估算。
Extra
含义:附加信息,提供了与操作有关联的信息。
三种类型:
- Using filesort:比较危险。说明 MySQL 会对数据使用一个外部的索引排序,而不是按照表内的索引顺序进行读取。MySQL 中无法利用索引完成的排序操作称之为文件排序,需要进行额外的步骤来发现如何对返回的行排序。
1 | mysql> explain select other_column from t1 where other_column = 'A' order by other_column3; |
优化案例:
1 | mysql> create index u_idx2 on t1(other_column,other_column2,other_column3); |
- Using temporary:比较危险,使用了临时表保存中间结果。这通常发生在对不同的列集进行
ORDER BY
上和GROUP BY
上,拖慢了查询速度。
1 | mysql> explain select other_column from t1 where other_column in ('A','B','C') group by other_column3; |
优化案例:
1 | mysql> explain select other_column from t1 where other_column in ('A','B','C') group by other_column,other_column2; |
Using index:表示相应的
select
操作中使用了覆盖索引,避免访问了表的数据行,效率不错。如果同时出现using where
,表明索引被用来执行索引键值的查找;如果没有同时出现using where
,表明索引用来读取数据而非执行查找动作。覆盖索引: 就是
select
的数据列只用从索引中就能够取得,不必读取数据行,MySQL 可以利用索引返回select
列表中的字段,而不必根据索引再次读取数据文件,换句话说查询列要被所建的索引覆盖。注意的是,如果要使用覆盖索引,一定要注意select
列表中只读取出需要的列,而不是select *
,因为如果将所有字段一起做索引会导致索引文件过大,降低查询性能。
1 | mysql> explain select other_column from t1 where other_column in ('A','B','C') group by other_column,other_column2; |
1 | mysql> explain select other_column,other_column2,other_column3 from t1; |
Tips: 在 show table status 结果中看到的 Rows 用于表示表的当前行数。对于 MyISAM 表这是一个精确值,但对InnoDB 这是个估算值。