举例来说,film_actor表的联合索引idx_film_actor_id由film_id和actor_id两个int列组成,并且每个int是4字节。通过下面结果中的key_len=4可推断出只使用了第一个列flim_id来执行索引查找。
执行SQL语句:EXPLAIN SELECT * FROM film_actor WHERE film_id=2
key_len计算规则如下:
① 字符串
char(n):n字节长度
varchar(n):2字节存储字符串长度,如果是UTF-8,则长度为3n+2
② 数值类型
tinyint:1字节
smallint:2字节
int:4字节
bigint:8字节
③ 时间类型
date:3字节
timestamp:4字节
datetime:8字节
④ 如果字段允许为NULL,需要1字节记录是否为NULL
(8)ref列
这一列显示了在key列记录的索引中,表查找值所用到的列或常量,常见的有:const(常量)、字段名(例:film.id)。
(9)rows列
这一列是MySQL估计要读取并检测的行数,注意这个不是结果集里的行数。
(10)Extra列
这一列展示的是额外信息。常见的重要值如下:
Using index: 查询的列被索引覆盖,并且where筛选条件是索引的前导列(类似联合索引的最左前缀原则),是性能高的表现。一般是使用了覆盖索引(即索引包含了所有查询的字段)。对于InnoDB来说,如果是普通索引性能会有不少提高。
执行SQL语句:EXPLAIN SELECT film_id FROM film_actor WHERE film_id=1
Using where:查询的列不完全被索引覆盖,where筛选条件非索引的前导列。(不走索引,性能较低)
执行SQL语句:EXPLAIN SELECT * FROM actor WHERE
Using where; Using index:查询的列被索引覆盖,并且where筛选条件是索引列之一但不是索引的前导列,意味着无法直接通过索引来查找符合条件的数据。
执行SQL语句:EXPLAIN SELECT film_id FROM film_actor WHERE actor_id=1
NULL:查询的列未被索引覆盖,并且where筛选条件是索引的前导列,意味着用到了索引,但是部分字段未被索引覆盖,必须通过“回表”来实现,不是纯粹地用到了索引,也不是完全没用到索引。
执行SQL语句:EXPLAIN SELECT * FROM film_actor WHERE film_id=1
Using index condition:MySQL 5.6版本开始加入的新特性,与Using where类似,查询的列不完全被索引覆盖,where条件中是一个前导列的范围。
执行SQL语句:EXPLAIN SELECT * FROM film_actor WHERE film_id>1
Using temporary:MySQL需要创建一张临时表来处理查询。出现这种情况一般是要进行优化的,首先要想到用索引来优化。
① actor.name没有索引,此时创建了一张临时表来distinct。(distinct:去除查询结果中的重复记录)
执行SQL语句:EXPLAIN SELECT DISTINCT NAME FROM actor
② film.name建立了idx_name索引,此时查询时extra是Using index,没有用临时表。
执行SQL语句:EXPLAIN SELECT DISTINCT NAME FROM film