侧边栏壁纸
博主昵称
流苏小筑

步伐虽小,密而不止

EXPLAIN:type字段详解

2024年01月22日 32阅读 0评论 0点赞

EXPLAIN:type字段详解

前文链接:https://mlsll.cn/archives/explain.html

执行计划的一条记录就代表着MySQL对某个表的 执行查询时的访问方法 , 又称“访问类型”,其中的 列就表明了这个访问方法是啥,是较为重要的一个指标。比如,看到 type 列的值是 type ref ,表明 MySQL 即将使用ref访问方法来执行对s1表的查询。
完整的访问方法如下: system , const , eq_ref , ref , fulltext , ref_or_null , index_merge , unique_subquery , index_subquery , range , index , ALL 。
我们详细解释一下:

①system

当表中只有一条记录并且该表使用的存储引擎的统计数据是精确的,比如MyISAM、Memory,那 么对该表的访问方法就是 system 。比方说我们新建一个 MyISAM 表,并为其插入一条记录:

mysql> CREATE TABLE t(i int) Engine=MyISAM;
Query OK, 0 rows affected (0.05 sec)

mysql> INSERT INTO t VALUES(1);
Query OK, 1 row affected (0.01 sec)

然后我们看一下查询这个表的执行计划: EXPLAIN SELECT * FROM t;
m4ezlunr.png
可以看到 type 列的值就是 system 了。

测试,可以把表改成使用InnoDB存储引擎,试试看执行计划的 const type 列是什么。ALL
m4ezml7t.png

②const

当我们根据主键或者唯一二级索引列与常数进行等值匹配时,对单表的访问方法就是 const , 比 如:

EXPLAIN SELECT * FROM s1 WHERE id = 10005;  

m4ezn4c1.png

③eq_ref

在连接查询时,如果被驱动表是通过主键或者唯一二级索引列等值匹配的方式进行访问的(如果该 主键或者唯一二级索引是联合索引的话,所有的索引列都必须进行等值比较)。则对该被驱动表的 访问方法就是 eq_ref ,比方说:

EXPLAIN SELECT * FROM s1 INNER JOIN s2 ON s1.id = s2.id;  

m4eznxqj.png
从执行计划的结果中可以看出,MySQL打算将s2作为驱动表,s1作为被驱动表,重点关注s1的访 问 方法是 eq_ref ,表明在访问s1表的时候可以 通过主键的等值匹配 来进行访问。

④ref

当通过普通的二级索引列与常量进行等值匹配时来查询某个表,那么对该表的访问方法就可能是 ref ,比方说下边这个查询:

EXPLAIN SELECT * FROM s1 WHERE key1 = 'a';  

m4ezoiwg.png

⑤fulltext

全文索引

⑥ref_or_null

当对普通二级索引进行等值匹配查询,该索引列的值也可以是 NULL 值时,那么对该表的访问方法 就可能是 ref_or_null ,比如说:

EXPLAIN SELECT * FROM s1 WHERE key1 = 'a' OR key1 IS NULL;  

m4ezp03d.png

⑦index_merge

一般情况下对于某个表的查询只能使用到一个索引,但单表访问方法时在某些场景下可以使用 Interseation、union、Sort-Union 这三种索引合并的方式来执行查询。我们看一下执行计划中 是怎么体现MySQL使用索引合并的方式来对某个表执行查询的:

EXPLAIN SELECT * FROM s1 WHERE key1 = 'a' OR key3 = 'a';  

m4ezpewu.png
从执行计划的 type 列的值是 index_merge 就可以看出,MySQL 打算使用索引合并的方式来执 行 对 s1 表的查询。

⑧unique_subquery

类似于两表连接中被驱动表的 eq_ref 访问方法, unique_subquery 是针对在一些包含 的查询语句中,如果查询优化器决定将IN子查询转换为 IN 子查询 EXISTS 子查询,而且子查询可以使用到主 键进行等值匹配的话,那么该子查询执行计划的 type 列的值就是 unique_subquery ,比如下边的 这个查询语句:

EXPLAIN SELECT * FROM s1 WHERE key2 IN (SELECT id FROM s2 where s1.key1 = s2.key1) OR key3 = 'a';

m4ezqfoy.png

⑨index_subquery

index_subquery 与 unique_subquery 类似,只不过访问子查询中的表时使用的是普通的索引,比如这样:

EXPLAIN SELECT * FROM s1 WHERE common_field IN (SELECT key3 FROM s2 where s1.key1 = s2.key1) OR key3 = 'a';

⑩range

范围区间

EXPLAIN SELECT * FROM s1 WHERE key1 IN ('a', 'b', 'c');  

m4ezrhbw.png
或者:

EXPLAIN SELECT * FROM s1 WHERE key1 > 'a' AND key1 < 'b';

m4ezs7o2.png

⑪index

当我们可以使用索引覆盖,但需要扫描全部的索引记录时,该表的访问方法就是样:
索引覆盖:不需要回表的查询
where条件使用了联合索引,而select的字段也全部包含在联合索引内,所以不需要回表就可以获取到要查询的数据。

EXPLAIN SELECT key_part2 FROM s1 WHERE key_part3 = 'a';

m4ezsrec.png
上述查询中的所有列表中只有key_part2 一个列,而且搜索条件中也只有 key_part3 一个列,这两 个列又恰好包含在idx_key_part这个索引中,可是搜索条件key_part3不能直接使用该索引进行 ref 和 range 方式的访问,只能扫描整个 值就是 index 。 idx_key_part 索引的记录,所以查询计划的 type 列的

再一次强调,对于使用InnoDB存储引擎的表来说,二级索引的记录只包含索引列和主键列的值,而聚簇索引中包含用户定义的全部列以及一些隐藏列,所以扫描二级索引的代价比直接全表扫描,也就是扫描聚簇索引的代价更低一些。

⑫ALL

最熟悉的全表扫描,就不多说了,直接看例子:

EXPLAIN SELECT * FROM s1;  

m4eztdi3.png

小结:

结果值从最好到最坏依次是:
system > const > eq_ref > ref > fulltext > ref_or_null > index_merge > unique_subquery > index_subquery > range > index > ALL
其中比较重要的几个提取出来(见上图中的粗体)。SQL 性能优化的目标:至少要达到 range 级别,要 求是 ref 级别,最好是 consts级别。(阿里巴巴 开发手册要求)

0

—— 评论区 ——

昵称
邮箱
网址
取消
博主栏壁纸
博主头像 流苏小筑

步伐虽小,密而不止

133 文章数
27 标签数
16 评论量