暂无图片
暂无图片
暂无图片
暂无图片
暂无图片

MySQL 8.0.19 Hash join

原创 CuiHulong 2020-03-05
3487

HASH JOIN:
MySQL 8.0.18 版本增加了一个新的特性hash join,关于hash join,通常其执行过程如下,首先基于join操作的一个表,在内存中创建一个对应的hash表,然后再一行一行的读另外一张表,通过计算哈希值,查找内存中的哈希表

hash join仅仅在join的字段上没有索引时才起作用,在此之前,不建议在没有索引的字段上做join操作,因为通常中这种操作会执行得很慢,但是有了hash join,它能够创建一个内存中的hash 表,代替之前的nested loop,使得没有索引的等值join性能提升很多。

准备数据:


####创建表
CREATE TABLE `t1` (
  `id` bigint(20) NOT NULL AUTO_INCREMENT,
  `name` varchar(255) DEFAULT NULL,
  `age` tinyint(4) DEFAULT NULL,
  `create_time` datetime DEFAULT NULL,
  `update_time` datetime DEFAULT NULL,
  PRIMARY KEY (`id`),
  key (name)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

CREATE TABLE `t2` (
  `id` bigint(20) NOT NULL AUTO_INCREMENT,
  `name` varchar(255) DEFAULT NULL,
  `age` tinyint(4) DEFAULT NULL,
  `create_time` datetime DEFAULT NULL,
  `update_time` datetime DEFAULT NULL,
  PRIMARY KEY (`id`),
  key (name)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

##创建批量数据 10000行数据
delimiter //
DROP PROCEDURE IF EXISTS proc_batch_insert;
CREATE PROCEDURE proc_batch_insert()
BEGIN
DECLARE pre_name BIGINT;
DECLARE ageVal INT;
DECLARE i INT;
SET pre_name=139;
SET ageVal=100;
SET i=1;
WHILE i <= 10000 DO
        INSERT INTO t1(`name`,age,create_time,update_time) VALUES(CONCAT(pre_name,'@qq.com'),(ageVal+1)*rand()%30,NOW(),NOW());
        INSERT INTO t2(`name`,age,create_time,update_time) VALUES(CONCAT(pre_name,'@qq.com'),(ageVal+1)*rand()%30,NOW(),NOW());
SET pre_name=pre_name+100;
SET i=i+1;
END WHILE;
END //

delimiter ;
##执行存储过程
call proc_batch_insert();

Hash Join怎样确认:
通过 explain format=tree 能够看到hash join是否被使用,这是新加的功能,而传统的explain仍然会显示nested loop,这种情况容易产生误解。

mysql> EXPLAIN FORMAT=TREE SELECT COUNT(*) FROM t1 INNER JOIN t2 ON t1.age=t2.age;
+-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| EXPLAIN                                                                                                                                                                                                                       
+-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| -> Aggregate: count(0)
    -> Inner hash join (t1.age = t2.age)  (cost=9824728.58 rows=9823708)
        -> Table scan on t1  (cost=0.01 rows=9939)
        -> Hash
            -> Table scan on t2  (cost=1012.65 rows=9884)
 |
+-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
1 row in set (0.00 sec)

测试:
MySQL8.0.19版本
1)索引情况下
image.png
2)Hash情况下
image.png

3)不走hash join 的性能因版本问题就没法测试。不管设置参数optimizer_switch=‘hash_join=off’ 也还是默认使用hash join开启的
下面是5.7.28版本的
image.png

结果对比:
hash join:0.3秒
基于索引的join:0.6秒
非hash join: 9秒
以上测试因为是本机的虚拟机,仅作为参考,但从结果对比可以看出,hash join执行性能确实提升很多。

配置hash join:
1.optimizer_switch 中的 hash_join=on/off,默认为onsql语句中指定HASH_JOIN或者NO_HASH_JOIN,
2.mysql 8.0.3引入的SET_VAR优化器提示还是很好用的,可用来设置语句级参数(oracle支持,mariadb记得也支持了的)

SELECT/*+ set_var(optimizer_switch='hash_join=off') set_var(join_buffer_size=4M) */  COUNT(*) FROM t1 INNER JOIN t2 ON t1.age=t2.age;
SELECT/*+ set_var(optimizer_switch='hash_join=off') set_var(join_buffer_size=4M) */  COUNT(*) FROM t1 INNER JOIN t2 ON t1.age=t2.age;

8.0.19版本测试过,基本无用。就是说无索引的字段默认走hash索引
官方解释如下:(HASH_JOIN, NO_HASH_JOIN: Enable or disable use of a hash join for the specified tables (MySQL 8.0.18 only; has no effect in MySQL 8.0.19 or later).
限制:
hash join只能在没有索引的字段上有效
hash join只在等值join条件中有效
hash join不能用于left join和right join最后:

hash join 是一个比较强大的join选项,也许这仅仅是一个开头,在不久的将来,基于它可能会延伸出更多更强大的特性,比如支持left join和right join等等。Hash join看到他的优点,在考虑一下缺点。毕竟刚上线需要实践中进行磨炼。希望对大家有所帮助

最后修改时间:2022-12-27 13:53:54
「喜欢这篇文章,您的关注和赞赏是给作者最好的鼓励」
关注作者
【版权声明】本文为墨天轮用户原创内容,转载时必须标注文章的来源(墨天轮),文章链接,文章作者等基本信息,否则作者和墨天轮有权追究责任。如果您发现墨天轮中有涉嫌抄袭或者侵权的内容,欢迎发送邮件至:contact@modb.pro进行举报,并提供相关证据,一经查实,墨天轮将立刻删除相关内容。

评论