

EXPLAIN,却等来的是无尽的折磨与抓狂。
explain命令,根据执行计划找到存在性能问题的SQL语句,以帮助我们优化SQL提供方向和依据。
一、执行计划?
EXPLAIN分析一条SQL语句时展示出来的那些信息。
EXPLAIN命令是查看查询优化器是如何决定执行查询的主要方法,从它的查询结果中可以知道一个SQL语句每一步是如何执行的,都经历了些什么,分为哪几步,有没有用到索引,哪些字段用到了什么样的索引,是否有一些可优化的地方等,这些信息都是我们SQL优化的依据。
EXPLAIN,只需在查询中的
SELECT关键字之前增加
EXPLAIN。语法如下:
EXPLAIN + SELECT查询语句;
当执行执行计划时,只会返回执行计划中每一步的信息,它会返回一行或多行信息,显示出执行计划中的每一部分和执行的次序。
如:

在接下来涉及到的示例表,均来自于MySQL官方的示例数据库 sakila
,脚本下载:https://downloads.mysql.com/docs/sakila-db.zip
二、执行计划中的列
EXPLAIN的结果总是有相同的列,每一列代表着不同的含义,可变的只是行数和内容。从上面的例子中,我们看到返回的有很多列,为了更加清楚的了解每一列的含义,便于我们更好的完成优化SQL。
| 列名 | 含义 |
|---|---|
| id | id列,表示查询中执行select子句或操作表的顺序。 |
| select_type | 查询类型,主要是用于区分普通查询、联合查询、子查询等复杂的查询。 |
| table | 表明对应行正在访问的是哪个表。 |
| partitions | 查询涉及到的分区。 |
| type | 访问类型,决定如何查找表中的行。 |
| possible_keys | 查询可以使用哪些索引。 |
| key | 实际使用的索引,如果为NULL,则没有使用索引。 |
| key_len | 索引中使用的字节数,查询中使用的索引的长度(最大可能长度),并非实际使用长度,理论上长度越短越好。 |
| ref | 显示索引的那一列被使用。 |
| rows | 估算出找到所需行而要读取的行数。 |
| filtered | 返回结果的行数占读取行数的百分比,值越大越好。 |
| Extra | 额外信息,但又十分重要。 |
1. id列
SELECT查询的序列号,表示执行SQL查询过程中
SELECT子句或操作表的顺序。
SELECT语句一般会顺序编号。
1)id相同
如下普通查询,没有子查询。
explain select f.* from film f,film_actor fa,actor a where f.film_id = fa.film_id and fa.actor_id = a.actor_id and a.first_name = 'NICK';
2)id不同
explain select * from film where film_id = (select film_id from film_actor where actor_id = 2 limit 1);
3)id相同又不同
2. select_type列
select_type列表示对应行的查询类型,是简单查询还是复杂查询,主要用于区分普通查询、联合查询、子查询等复杂的查询。
select_type列有如下值:
| select_type值 | 说明 |
|---|---|
| SIMPLE | 简单查询,意味着不包括子查询或UNION。 |
| PRIMARY | 查询中包含任何复杂的子部分,最外层查询则被标记为PRIMARY |
| SUBQUERY | 在select或 where列表中包含了子查询 |
| DERIVED | 表示包含在from子句的子查询中的 select,MySQL会递归执行并将结果放到一个临时表中,称其为“派生表”,因为该临时表是从子查询中派生而来的。 |
| UNION | 第二个select出现在UNION之后,则被标记为 UNION。 |
| UNION RESULT | 从UNION表获取结果的 select。 |
3. table列
table列表示对应行正在执行的哪张表,指代对应表名,或者该表的别名(如果SQL中定义了别名)。
4. partitions列
查询涉及到的分区。
5. type列
type列指代访问类型,是MySQL决定如何查找表中的行。
ALL < index < range < index_subquery < unique_subquery < index_merge < ref_or_null < fulltext < ref < eq_ref < const < system
1)ALL
explain select * from film;
select *,就不难理解了。换言之,是为了避免全表扫描,因为全面扫描是性能最差的。
2)index
ALL类似,扫描表时按索引次序进行,而不是按行扫描,即:只遍历索引树。
index与
ALL虽然都是读全表,但
index是从索引中读取,而ALL是从硬盘读取。显然,
index性能上优于
ALL,合理的添加索引将有助于性能的提升。
explain select title from film;
explain select description from film;

film中字段
title时,是按照索引扫描的(
type列为
index),倘若查询字段
description,却是按照全表扫描的(
type列为
ALL)。这是为何呢?

desc film结果来看,字段
title创建的有索引,而字段
description没有,所以
select title from film是按索引扫描,而
select description from film按全表扫描。
3)range
key列显示使用了那个索引。一般就是在
where语句中出现了
bettween、<、>、in等的查询。这种索引列上的范围扫描比全索引扫描
index要好。
explain select * from film where film_id between 1 and 10;
4)ref
show index from film;
explain select * from film where title = 'ACADEMY DINOSAUR';

5)eq_ref
唯一索引扫描。常见于主键或唯一索引扫描。
6)const
const用于比较
primary key或者
unique索引。因为只需匹配一行数据,所有很快。如果将主键置于
where列表中,mysql就能将该查询转换为一个
const。
show index from film;
explain select * from film where film_id = 1;

7)system
表只有一行记录,这是const类型的特例,比较少见,如:系统表。
6. possible_keys列
显示在查询中使用了哪些索引。
7. key列
NULL,则没有使用索引。查询中如果使用了覆盖索引,则该索引仅出现在key列中。
possible_keys列表明哪一个索引有助于更高效的查询,而
key列表明实际优化采用了哪一个索引可以更加高效。
show index from film_actor;
explain select actor_id,film_id from film_actor;

8. key_len列
key_len是根据表定义计算而得的,不是通过表内检索出的。
9. ref列
表示在key
列记录的索引中查找值,所用的列或常量const
。
10. rows列
11. filtered列

12. Extra列
额外信息,但又十分重要。
常见的值如下:
1)Using index
表示SQL中使用了覆盖索引。
举例如下:

2)Using where
where条件里是涉及索引中的列,当它读取索引时,就能被存储引擎检验,因此不是所有带·
where子句的查询都会显示
“Using where”。
3)Using temporary
order by和
group by。
4)Using filesort
三、总结
SQL如何使用索引 复杂SQL的执行顺序 查询扫描的数据函数 ……

MySQL性能优化(一):MySQL架构与核心问题 MySQL性能优化(二):选择优化的数据类型 微服务架构下的核心话题 (二):微服务架构的设计原则和核心话题 微服务架构下的核心话题 (三):微服务架构的技术选型

喜欢就点个"在看"呗,留言、转发朋友圈
文章转载自程序猿技术大咖,如果涉嫌侵权,请发送邮件至:contact@modb.pro进行举报,并提供相关证据,一经查实,墨天轮将立刻删除相关内容。




