📫 作者简介:「子非我鱼」,专注于研究全栈
🔥 三连支持:欢迎 ❤️关注、👍点赞、👉收藏三连,支持一下博主~
文章目录
引言
MySQL 提供了一个强大的工具,称为 EXPLAIN
,它允许你深入了解查询语句的执行计划,从而有助于优化查询性能。通过 EXPLAIN
,你可以查看 MySQL 是如何处理查询的,包括它选择的索引、连接类型、访问的表等信息。本文将介绍如何使用 EXPLAIN
工具来优化 MySQL 查询性能。
1,Explain工具介绍
使用EXPLAIN关键字可以模拟优化器执行SQL语句,分析你的查询语句或是结构的性能瓶颈
在 select 语句之前增加 explain 关键字 ,MySQL 会在查询上设置一个标记,执行查询会返回执行计划的信息,而不是执行这条SQL
注意:如果 from 中包含子查询,仍会执行该子查询,将结果放入临时表中
2,基本语法
使用 EXPLAIN
的基本语法如下:
EXPLAIN SELECT * FROM your_table WHERE your_condition;
或者
EXPLAIN your_query;
3,分析输出
示例表:
DROP TABLE IF EXISTS `actor`;
CREATE TABLE `actor` (
`id` int(11) NOT NULL,
`name` varchar(45) DEFAULT NULL,
`update_time` datetime DEFAULT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
INSERT INTO `actor` (`id`, `name`, `update_time`) VALUES (1,'a','2017-12-22 15:27:18'), (2,'b','2017-12-22 15:27:18'), (3,'c','2017-12-22 15:27:18');
DROP TABLE IF EXISTS `film`;
CREATE TABLE `film` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`name` varchar(10) DEFAULT NULL,
PRIMARY KEY (`id`),
KEY `idx_name` (`name`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
INSERT INTO `film` (`id`, `name`) VALUES (3,'film0'),(1,'film1'),(2,'film2');
DROP TABLE IF EXISTS `film_actor`;
CREATE TABLE `film_actor` (
`id` int(11) NOT NULL,
`film_id` int(11) NOT NULL,
`actor_id` int(11) NOT NULL,
`remark` varchar(255) DEFAULT NULL,
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`) VALUES (1,1,1),(2,1,2),(3,2,1);
# 关闭mysql新特性对衍生表的合并优化(示例的时候执行)
set session optimizer_switch='derived_merge=off';
# 开启mysql新特性对衍生表的合并优化(示例结束后恢复)
set session optimizer_switch='derived_merge=on';
EXPLAIN
返回一张表,其中包含有关查询执行计划的信息。以下是一些关键列:
id
查询的标识符,用于标识查询中的不同步骤。正常情况下有几个select语句就有几行id(表连接特殊),id值越大优先级越高,id值相同,自上而下执行,id为null的最后执行
select_type
查询的类型,表示对应行可以是简单查询、联合查询、子查询等。
(1)simple:简单查询。查询不包含子查询和union
(2)primary:复杂查询中最外层的 select
(3)subquery:包含在 select 中的子查询(不在 from 子句中)
(4)derived:包含在 from 子句中的子查询。MySQL会将结果存放在一个临时表中,也称为派生表(derived的英文含义)
(5)union:在 union 中的第二个和随后的 select
table
正在访问的表,当 from 子句中有子查询时,table列是 格式,表示当前查询依赖 id=N 的查询,于是先执行 id=N 的查询。
当有 union 时,UNION RESULT 的 table 列的值为<union1,2>,1和2表示参与 union 的 select 行id。
type
这一列表示关联类型或访问类型,即MySQL决定如何查找表中的行,查找数据行记录的大概范围。
依次从最优到最差分别为:system > const > eq_ref > ref > range > index > ALL
一般来说,得保证查询达到range级别,最好达到ref
NULL:mysql能够在优化阶段分解查询语句,在执行阶段用不着再访问表或索引。例如:在索引列中选取最小值,可以单独查找索引来完成,不需要在执行时访问表
(1)system,const:mysql能对查询的某部分进行优化并将其转化成一个常量。用于 primary key 或 unique key 的所有列与常数比较时,所以表最多有一个匹配行,读取1次,速度比较快。system是const的特例,表里只有一条元组匹配时为system
(2)eq_ref:primary key 或unique key 索引的所有部分被连接使用 ,最多只会返回一条符合条件的记录。这可能是在 const 之外最好的联接类型了,简单的 select 查询不会出现这种 type
(3)ref:相比 eq_ref,不使用唯一索引,而是使用普通索引或者唯一性索引的部分前缀,索引要和某个值相比较,可能会找到多个符合条件的行
(4)range:范围扫描通常出现在 in(), between ,> ,<, >= 等操作中。使用一个索引来检索给定范围的行
(5)index:扫描全索引就能拿到结果,一般是扫描某个二级索引,这种扫