MySQL优化器hash join怎么使用

103次阅读
没有评论

共计 2060 个字符,预计需要花费 6 分钟才能阅读完成。

今天丸趣 TV 小编给大家分享一下 MySQL 优化器 hash join 怎么使用的相关知识点,内容详细,逻辑清晰,相信大部分人都还太了解这方面的知识,所以分享这篇文章给大家参考一下,希望大家阅读完这篇文章后有所收获,下面我们一起来了解一下吧。

前言

数据库的优化器相当于人类的大脑,大部分时候都能做出正确的决策,制定正确的执行计划,走出一条高效的路,但是它毕竟是基于某些固定的规则、算法来做的判断,有时候并没有我们人脑思维灵活,当我们确定优化器选择执行计划错误时该怎么办呢,语句上加 hint,提示它选择哪条路是一种常见的优化方法。

我们知道 Oracle 提供了比较灵活的 hint 提示来指示优化器在多表连接时选择哪种表连接方式,比如 use_nl,no_use_nl 控制是否使用 Nest Loop Join,use_hash,no_use_hash 控制是否使用 hash join。

但是 MySQL 长期以来只有一种表连接方式,那就是 Nest Loop Join,直到 MySQL8.0.18 版本才出现了 hash join,所以 MySQL 在控制表连接方式上没有提供那么多丰富的 hint 给我们使用,hash_join 与 no_hash_join 的 hint 只是惊鸿一瞥,只在 8.0.18 版本存在,8.0.19 及后面的版本又将这个 hint 给废弃了,那如果我们想让两个表做 hash join 该怎么办呢?

实验

我们来以 MySQL8.0.25 的单机环境做一个实验。建两个表,分别插入 10000 行数据,使用主键做这两个表的关联查询。

create table t1(id int primary key,c1 int,c2 int);
create table t2(id int primary key,c1 int,c2 int);
delimiter //
CREATE PROCEDURE p_test()
BEGIN
declare i int;
set i=1;
while i 10001 do
insert into t1 values(i,i,i);
insert into t2 values(i,i,i);
SET i = i + 1;
end while;
delimiter ;

查询一下两表使用主键字段关联查询时实际的执行计划,如下图所示:

查询一下两表使用非索引字段关联查询时实际的执行计划,如下图所示:

从执行计划可以看出,被驱动表的关联字段上有索引,优化器在选择表连接方式时会倾向于选择 Nest Loop Join,当没有可用索引时倾向于选择 hash join。

基于这一点那我们可以使用 no_index 提示来禁止语句使用关联字段的索引。

从上面的执行计划可以看出使用 no_index 提示后,优化器选择了使用 hash join。

当索引的选择性不好时,优化器选择使用索引做 Nest Loop Join 是效率是很低的。

我们将实验的两个表中 c1 列的数据做一下更改, 使其选择性变差,并在 c1 列上建普通索引。

update t1 set c1=1 where id 5000;
update t2 set c1=1 where id 5000;
create index idx_t1 on t1(c1);
create index idx_t2 on t2(c1);

当我们执行 sql:

select t1.*,t2.* from t1 join t2 on t1.c1=t2.c1;

这个查询结果会返回大量数据,被驱动表的关联字段 c1 列的索引选择性差,此时选择 hash join 是更明智的选择,但是优化器会选择走 Nest Loop Join。我们可以通过实验验证一下 hash join 与 Nest Loop Join 的性能差异。

可以看出使用 hash join 的耗时是使用 Nest Loop Join 的 1 /6,但是优化器根据成本估算时,使用 Nest Loop Join 的成本要比使用 hash join 的成本低很多,所以会去选择 Nest Loop Join,这个时候就需要加上 hint 提示禁止使用关联字段的索引,被驱动表上每次都全表扫描的代价是很高的,这样优化器估算后就会选择走 hash join。

MySQL 官方文档里提到用 BNL,NO_BNL 的 hint 提示来影响 hash join 的优化,但是经过实验证明,在表连接关联字段上没有可用索引时,优化器估算成本后不会对被驱动表使用 BNL 全表扫描的方式做嵌套循环连接,而是会选择使用 hash join,那这样 NO_BNL 在这个场景下就没有用武之地了。

那么既然不用这个索引,把这个索引去掉不就可以了吗?为什么非要使用 no_index 的 hint 提示呢,我们要知道业务使用的场景何其多,此处不用,别处使用了这个索引效率可能会有大的提升啊,这个时候就凸显了 hint 的优势,只需要控制此语句的使用就好了。

以上就是“MySQL 优化器 hash join 怎么使用”这篇文章的所有内容,感谢各位的阅读!相信大家阅读完这篇文章都有很大的收获,丸趣 TV 小编每天都会为大家更新不同的知识,如果还想学习更多的知识,请关注丸趣 TV 行业资讯频道。

正文完
 
丸趣
版权声明:本站原创文章,由 丸趣 2023-07-13发表,共计2060字。
转载说明:除特殊说明外本站除技术相关以外文章皆由网络搜集发布,转载请注明出处。
评论(没有评论)