1、何为explain执行计划?
使用explain关键字可以模拟优化器执行SQL语句,从而知道MySQL是如何使用索引来处理你的SQL查询语句以及连接表,可以分析查询语句或是结构的性能瓶颈,帮助我们选择更好的索引和写出更优化的查询语句。(说白了,就是优化SQL的工具)
2、如何使用explain?
在你的SQL查询语句前加上 explain 即可,如explain select * from table,MySQL会在查询上设置一个标记,执行查询时,会返回执行计划的信息,而不是执行这条SQL(如果 from 中包含子查询,仍会执行该子查询,将结果放入临时表)。
3、使用explain的例子
需要使用三张表,分别为 actor 演员表,film 电影表,film_actor 电影-演员关联表。
CREATE TABLE `actor` (
`id` int(11) NOT NULL COMMENT '主键id',
`name` varchar(45) DEFAULT NULL COMMENT '演员名称',
`update_time` datetime DEFAULT NULL COMMENT '修改时间',
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
insert into `actor` (`id`, `name`, `update_time`) values('1','a','2020-02-11 22:56:00');
insert into `actor` (`id`, `name`, `update_time`) values('2','b','2020-02-11 22:56:00');
insert into `actor` (`id`, `name`, `update_time`) values('3','c','2020-02-11 22:56:00');
CREATE TABLE `film` (
`id` int(11) NOT NULL AUTO_INCREMENT COMMENT '主键id',
`name` varchar(10) DEFAULT NULL COMMENT '电影名称',
PRIMARY KEY (`id`),
KEY `idx_name` (`name`)
) ENGINE=InnoDB AUTO_INCREMENT=4 DEFAULT CHARSET=utf8;
insert into `film` (`id`, `name`) values('3','film0');
insert into `film` (`id`, `name`) values('1','film1');
insert into `film` (`id`, `name`) values('2','film2');
CREATE TABLE `film_actor` (
`id` int(11) NOT NULL COMMENT '主键id',
`film_id` int(11) NOT NULL COMMENT '电影id',
`actor_id` int(11) NOT NULL COMMENT '演员id',
`remark` varchar(255) DEFAULT NULL COMMENT '备注',
PRIMARY KEY (`id`),
KEY `idx_film_actor_id` (`film_id`,`actor_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
insert into `film_actor` (`id`, `film_id`, `actor_id`, `remark`) values('1','1','1',NULL);
insert into `film_actor` (`id`, `film_id`, `actor_id`, `remark`) values('2','1','2',NULL);
insert into `film_actor` (`id`, `film_id`, `actor_id`, `remark`) values('3','2','1',NULL);
执行完以上SQL后,三张表数据对应如下:
下面展示explain中每个列的信息:
(1)id列
id列的编号是select语句的序列号,有几个 select 就有几个id,并且id的序号是按 select 出现的顺序而增长的(id越大,对应的select语句越先执行,如果id相等,则从上往下执行,id为NULL最后执行)。
MySQL将select查询分为简单查询(SIMPLE)和复杂查询(PRIMARY)。
复杂查询分为三类:简单子查询、派生表(from语句中的子查询)、union查询。
1)简单子查询
执行SQL语句:EXPLAIN SELECT (SELECT 1 FROM actor LIMIT 1) FROM film
2)from子句中的子查询
执行SQL语句:EXPLAIN SELECT id FROM (SELECT id FROM film) AS der
分析:这个查询执行时有个临时表别名为der,外部select查询引用了这个临时表。
3)union查询
执行SQL语句:EXPLAIN SELECT 1 UNION ALL SELECT 1
分析:union结果总是放在一个匿名临时表中,临时表不在SQL中出现,因此它的id为NULL。(不推荐使用union,性能不高)
(2)select_type列
这一列表示对应行是简单还是复杂查询,如果是复杂查询,又是上述三种复杂查询中的哪一种。
1)SIMPLE:简单查询。查询不包含子查询和union。
执行SQL语句:EXPLAIN SELECT * FROM film WHERE id=2
2)PRIMARY:复杂查询中最外层的select。
3)SUBQUERY:包含在select中的子查询(不在from子句中)。
4)DERIVED:包含在from子句中的子查询。MySQL会将结果存放在一个临时表中,也称为派生表(DERIVED的英文含义)。
执行SQL语句:EXPLAIN SELECT (SELECT 1 FROM actor WHERE id=1) FROM (SELECT * FROM film WHERE id=1) der
5)UNION:在union中的第二个和随后的select。
6)UNION RESULT:从union临时表检索结果的select。
执行SQL语句:EXPLAIN SELECT 1 UNION ALL SELECT 1
(3)table列
这一列表示explain的一行正在访问哪个表。
当from子句中有子查询时,table列是<DERIVED N>格式,表示当前查询依赖id=N的查询,于是先执行id=N的查询。
当有union时,UNION RESULT的table列的值为<union 1,2>,1和2表示参与union的select行id。
(4)type列
(温馨提示:以下部分理论有可能解释完还是懵逼,没关系,继续往下看,有实践例子)
这一列表示关联类型或访问类型,即MySQL决定如何查找表中的行,查找数据记录的大概范围。
SQL语句查询效率从最优到最差依次为:system > const > eq_ref > ref > range > index > ALL。
一般来说,得保证查询达到range级别,最好达到ref。