MYSQL 的多表联合查询中,只有nest loop 的查询方式,让MYSQL 一致是被“嘲笑”的地方。MYSQL 8.018 后mysql 将拥有HASH JOIN 功能,虽然对比其他数据库来说,这并不新鲜,但对于MYSQL 算是划时代的里程碑。
原理之类的先不说,先看效果。建立两个存储过程,为C1 表和 C2表插入测试数据
delimiter //
CREATE PROCEDURE insert_c1()
BEGIN
DECLARE i int ;
DECLARE a varchar(20) ;
DECLARE b smallint ;
set i = 1;
begin
WHILE i<=1000000 do
set b = FLOOR(rand()*50);
if i mod 2 = 0 then
set a = 'good';
elseif i mod 3 = 0 then
set a = 'excellent';
elseif i mod 5 = 0 then
set a = 'ordinary';
elseif i mod 4 = 0 then
set a = 'worsen';
else
set a = 'improvement';
end if;
if b < 20 then
set b = b + 15;
end if;
INSERT into test.status(status,score) values (a,b);
set i = i + 1;
END WHILE;
end;
END
//
两个表结构是一样的
CREATE TABLE `t1` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`c1` varchar(20) DEFAULT NULL,
`c2` int(11) DEFAULT NULL,
PRIMARY KEY (`id`),
KEY `idx_c1` (`c1`)
) ENGINE=InnoDB
从图中可以清晰的看到查询已经走了hash join,那老的MYSQL DBA 可能会提出一个问题,到底这个hash join 比 nest loop 能好多少,可别和MYSQL 8 VS MYSQL 5.7一样,谁快还不一定。下面做了一个对比,可以清晰的看到在某些情况下,HASH JOIN 在没有索引的情况下,比添加了索引的NEST LOOP 的速度要快了一倍。
所以到这里,
1 hash join 的确是查询中需要的功能
2 hash join 的确在某些情况下 比 NEST LOOP 要快
在说明完这些问题后,我们的讲讲为什么
在MYSQL 中hash join的构造包含两个流程 1 build 2 probe
1建立的阶段就是将需要进行JOIN 的字段,进行一个HASH 值的计算,而到底哪个表要进行这样的计算,整体SIZE 小的表将被选中,在内存中构建这个计算好值的表
2 匹配的过程,从另外一个表中将字段的值进行计算,与内存中的值匹配的就被选中,否则就抛弃。
这样操作的好处也是显而易见的,大大缩减比对的次数
NEST LOOP 如果是 N * S 则 hash join 可以比对为N * distinct S 如果distinct S 变化的值越少,则表的查询速度越快。
当然这样还会产生另一个结果,就是我们可以在某些时候放弃JOIN 中建立索引了,如果建立了索引,则MYSQL 会倾向使用 NEST LOOP ,而不走HASH JOIN ,所以到了8.018 这个版本后,MYSQL 的查询优化,可能又要添加一条想法了。
当然如果想要这个功能,首先先查查你的数据库目前支持,或打开了这个功能没有。
那hash joinj就无敌了,哪里都能用 NO NO NO 要使用它是有限制的,我们下面吧索引删除
下面的查询看似和上面的差不多,但就是没有走HASH JOIN
所以需要记住三个地方是是否能使用HASH JOIN 的前提
1 没有索引
2 等值运算
3 INNER JOIN
如果有兴趣可以加个群,共同提高