explain的使用很简单,只要在select语句的前面加上explain
的关键字就好了,来看个例子
先创建两个表,注意两个表的索引
CREATE TABLE `user` (
`id` varchar(32) NOT NULL,
`name` varchar(32) DEFAULT NULL,
`role` varchar(32) DEFAULT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
INSERT INTO `user` VALUES ('1', '1', '1');
INSERT INTO `user` VALUES ('10', '10', '5');
INSERT INTO `user` VALUES ('2', '2', '2');
INSERT INTO `user` VALUES ('3', '3', '3');
INSERT INTO `user` VALUES ('4', '4', '4');
INSERT INTO `user` VALUES ('5', '5', '5');
INSERT INTO `user` VALUES ('6', '6', '1');
INSERT INTO `user` VALUES ('7', '7', '2');
INSERT INTO `user` VALUES ('8', '8', '3');
INSERT INTO `user` VALUES ('9', '9', '4');
CREATE TABLE `role` (
`id` varchar(32) NOT NULL,
`name` varchar(32) DEFAULT NULL,
PRIMARY KEY (`id`),
KEY `name` (`name`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
INSERT INTO `role` VALUES ('1', '1');
INSERT INTO `role` VALUES ('6', '1');
INSERT INTO `role` VALUES ('2', '2');
INSERT INTO `role` VALUES ('3', '3');
INSERT INTO `role` VALUES ('4', '4');
INSERT INTO `role` VALUES ('5', '5');
试一下explain
EXPLAIN SELECT * FROM `user` WHERE id = '1'
来看输出结果,表格太长了,就不以表格的形式显示结果了
id: 1
select_type : SIMPLE
table: user
type: const
possible_keys: PRIMARY
key: PRIMARY
ken_len: 98
ref: const
rows: 1
Extra: NULL
来看看各个字段的含义:
有两个字段(partitions,filtered)没有在查询的结果中出现,一般也不需要关注这两个字段,同时所有的字段并不是全部是重要的,这里来详细了解下各个字段。
id的值说明了sql执行的先后顺序,可能出现三种情况:
id相同时,执行的顺序是自上到下依次运行
比如使用子查询的情况下,会出现id的值递增的情况。id的值越大执行的优先级越高。
可以把相同的理解为一组,相同一组的执行顺序自上到下依次运行,不同组的id的值越大,执行的优先级越高。
select_type的值主要有以下几种:
简单的select
,不使用UNION或子查询
例子
EXPLAIN SELECT * FROM `user` WHERE id = '1'
最外层查询的select
查询
例子
EXPLAIN SELECT * FROM `user`
WHERE role = (
SELECT id FROM role
WHERE `name` = '1'
)
UNION
查询中的第二个语句或后面的语句
例如
EXPLAIN SELECT * FROM `user` WHERE id = '1'
UNION
SELECT * FROM `user` WHERE id = '2'
UNION查询中的第二个或后面的查询语句, 取决于外面的查询, 即子查询依赖于外层查询的结果.
UNION查询的结果
例如
EXPLAIN SELECT * FROM `user` WHERE id = '1'
UNION
SELECT * FROM `user` WHERE id = '2'
子查询中的第一个select
例如
EXPLAIN SELECT * FROM `user`
WHERE role = (
SELECT id FROM role
WHERE `name` = '1'
)
子查询中的第一个select
,取决于外面的查询。
table
表示该次查询涉及到的表名或表的别名。
type
是一个非常重要的一个字段。根据type
字段可以判断查询是否性能高效。
常用的类型有:
表示结果集仅有一行,这是const
类型的一个特例,一般是在myisam
或memory
存储引擎中,在innodb
存储引擎中为const
表示通过主键或者唯一索引查找数据时只匹配了一行数据,const
说明查询速度非常快。
例子
EXPLAIN SELECT * FROM `user` WHERE id = '1'
多出现在联接查询,表示索引是主键或唯一非 NULL 索引时,对于前表的每一个结果, 都只能匹配到后表的一行结果. 并且查询的比较操作通常是 =, 查询效率较高,这是最好的联接类型。
例子
EXPLAIN SELECT * FROM `user`,role
WHERE `user`.id = role.`id`
说明:
user.id
是唯一索引, 每条user.id
可以联接role
中的一条数据。
通常出现在多表的联接查询, 针对于非唯一或非主键索引, 或者是使用了 最左前缀 规则索引的查询.
例子:
EXPLAIN SELECT * FROM `user`,role
WHERE `user`.`name` = role.name
说明:role.name
是索引,但并不是唯一索引和主键索引
表示使用索引范围查询,这个类型通常出现在 =, <>, >, >=, <, <=, IS NULL, <=>, BETWEEN, IN() 操作中。
例子
EXPLAIN SELECT * FROM `user`
WHERE id IN ('1','2','3')
表示全索引扫描,扫描所有的索引
例子
EXPLAIN SELECT id,`name` FROM `role`
表示全表扫描,这是最坏的结果。
最好的结果到最差的结果:system > const > eq_ref > ref > range > index > ALL,一般来说,得保证查询至少达到range级别,最好能达到ref。
可能用到的索引。注意:只是可能。即使有些索引在这个字段中出现。也不一定会被真正用到。
实际被用到的索引列。注意和possible_keys
做区分
表示索引中使用的字节数,key_len显示的值为索引字段的最大可能长度,并非实际使用长度。这个当然越短越好。
表示上述表的连接匹配条件,即哪些列或常量被用于查找索引列上的值
rows
这个也是非常重要的一个字段,估算要扫描的行数,原则上越少越好。注意:这个值并不是完全准确的值,只是估算。
Extra
提供了多个值,这只说几个比较常见的,有兴趣的少侠可以自行百度,谷歌。
查询时需要用额外的临时表来存储结果集,比较常见在group by
,order by
中。
当包含order by
操作,而且无法利用索引完成的排序操作称为“文件排序”,建议优化。
在获取连接条件时没有使用索引,并且需要连接缓冲区来存储中间结果。如果出现了这个值,那应该注意,根据查询的具体情况可能需要添加索引来改进能。
“覆盖索引”,表示查询的数据在索引中就可以找到,说明性能不错。
explain
只能解释select
explain
不计算各种Cache