news 2026/10/31 7:04:24

面试官:MySQL 8.0版本引入的 hash join 有什么优势?

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
面试官:MySQL 8.0版本引入的 hash join 有什么优势?

MySQL 在 8.0.18 中引入 hash join,这是一个为 join 查询语句设计的高效算法。今天来介绍一下 hash join。

1.简介

首先我们建立两张表,SQL 如下:

CREATE TABLE t1 (c1 INT, c2 INT); CREATE TABLE t2 (c1 INT, c2 INT);

再给出一个连接查询 SQL:

SELECT * FROM t1 JOIN t2 ON t1.c1=t2.c1;

那 hash join 的执行过程是怎样的呢?

1.确定驱动表(MySQL 会选择结果集较小的表作为驱动表),将结果集加载到内存中;

2.以连接键为 hash key 构建 hash 表,使用链表法解决 hash 冲突。

3.对于非驱动表,依次扫描每一行数据,对 join 字段取 hash 值,然后在 2 构建的 hash 表中查找这个 hash 值;

4.如果找到,则对这个 hash 值所在的链表上每个值进行等值比较,如果比较结果一致,则结合两个表的相关字段生成结果集并输出;

5.如果找不到,则继续扫描下一行。 整个过程如下图:

hash join 的时间复杂度是多少呢?假如 t1 表的记录数是 M,扫描 t1 表的时间复杂度是 o(M),t2 表的记录数是 N,扫描 t2 表的时间复杂度是 o(N),hash 表查询的复杂度是 o(1),这样使用 hash join 查找的总时间复杂度是 o(M + N)。

2.优势

在上面的例子中,t1 表和 t2 表都没有加索引,如果做 join 查询,在 MySQL 8.0 以前,会使用 BNL 算法。

BNL 算法流程如下:

1.把 t1 表的数据读出放到 join_buffer;

2.扫描 t2 表中的每一行,用 c1 字段值跟 join_buffer 中 t1 表的 c1 字段值做比较;

3.如果 c1 值一样,则作为结果集返回,如果不一样,则继续扫描 t2 表下一行。

join_buffer 是一个无序数组,t2 表中的每一行都需要跟 t1 表的所有记录做比对。假如 t1 表的数据量是 M,t2 表的数据量是 N,则需要比对的次数是 M * N,也就是说时间复杂度是 o(M*N)。

从时间复杂度可以明显看出 hash join 的优势。

从 MySQL 8.0.20 开始,不再支持 BNL 算法,server 在原先使用 BNL 算法的地方使用 hash join。

3.hash join 优化

MySQL 8.0.18 引入 hash join,主要用于 join 语句中有等值条件并且 join 条件中不能使用索引的场景。比如前面例子中的 join 语句,t1 和 t2 的 c1 字段都没有索引:

SELECT * FROM t1 JOIN t2 ON t1.c1=t2.c1;

3.1 配置

MySQL 8.0.18 版本中,支持设置 hash_join=on 或 hash_join=off 供优化器选择,在 MySQL 8.0.19 及更高版本中,这个设置不再生效,server 会默认使用 hash join。

3.2 连接条件优化

优化一:在 MySQL 8.0.20 以前,如果 join 条件中存在一个非等值匹配的条件,就会走 BNL 算法。MySQL 8.0.20 以后,即使有非等值条件,也会走 hash join。下面 SQL 来自官网:

mysql> EXPLAIN FORMAT=TREE -> SELECT * FROM t1 -> JOIN t2 ON (t1.c1 = t2.c1) -> JOIN t3 ON (t2.c1 < t3.c1)\G *************************** 1.row *************************** EXPLAIN: -> Filter: (t1.c1 < t3.c1) (cost=1.05rows=1) -> Innerhashjoin (no condition) (cost=1.05rows=1) -> Tablescanon t3 (cost=0.35rows=1) -> Hash -> Innerhashjoin (t2.c1 = t1.c1) (cost=0.70rows=1) -> Tablescanon t2 (cost=0.35rows=1) -> Hash -> Tablescanon t1 (cost=0.35rows=1)

优化二:即使 join 没有条件,也会走 hash join:

mysql> EXPLAIN FORMAT=TREE -> SELECT * -> FROM t1 -> JOIN t2 -> WHERE t1.c2 > 50\G *************************** 1.row *************************** EXPLAIN: -> Innerhashjoin (cost=0.70rows=1) -> Tablescanon t2 (cost=0.35rows=1) -> Hash -> Filter: (t1.c2 > 50) (cost=0.35rows=1) -> Tablescanon t1 (cost=0.35rows=1)

优化三:即使 join 条件中没有等值条件,也会走 hash join。下面 5 个示例来自官网,都会走 hash join。

1.内连接无等值条件:

mysql> EXPLAIN FORMAT=TREE SELECT * FROM t1 JOIN t2 ON t1.c1 < t2.c1\G *************************** 1.row *************************** EXPLAIN: -> Filter: (t1.c1 < t2.c1) (cost=4.70rows=12) -> Innerhashjoin (no condition) (cost=4.70rows=12) -> Tablescanon t2 (cost=0.08rows=6) -> Hash -> Tablescanon t1 (cost=0.85rows=6)

2.半连接:

mysql> EXPLAIN FORMAT=TREE SELECT * FROM t1 -> WHERE t1.c1 IN (SELECT t2.c2 FROM t2)\G *************************** 1.row *************************** EXPLAIN: -> Hash semijoin (t2.c2 = t1.c1) (cost=0.70rows=1) -> Tablescanon t1 (cost=0.35rows=1) -> Hash -> Tablescanon t2 (cost=0.35rows=1)

3.反连接:

mysql> EXPLAIN FORMAT=TREE SELECT * FROM t2 -> WHERE NOT EXISTS (SELECT * FROM t1 WHERE t1.c1 = t2.c1)\G *************************** 1.row *************************** EXPLAIN: -> Hash antijoin (t1.c1 = t2.c1) (cost=0.70rows=1) -> Tablescanon t2 (cost=0.35rows=1) -> Hash -> Tablescanon t1 (cost=0.35rows=1) 1rowinset, 1warning (0.00 sec) mysql> SHOWWARNINGS\G *************************** 1.row *************************** Level: Note Code: 1276 Message: Fieldorreference't3.t2.c1'ofSELECT#2 was resolved in SELECT #1

4.左外连接:

mysql> EXPLAIN FORMAT=TREE SELECT * FROM t1 LEFTJOIN t2 ON t1.c1 = t2.c1\G *************************** 1.row *************************** EXPLAIN: -> Lefthashjoin (t2.c1 = t1.c1) (cost=0.70rows=1) -> Tablescanon t1 (cost=0.35rows=1) -> Hash -> Tablescanon t2 (cost=0.35rows=1)

5.右外连接:

mysql> EXPLAIN FORMAT=TREE SELECT * FROM t1 RIGHTJOIN t2 ON t1.c1 = t2.c1\G *************************** 1.row *************************** EXPLAIN: -> Lefthashjoin (t1.c1 = t2.c1) (cost=0.70rows=1) -> Tablescanon t2 (cost=0.35rows=1) -> Hash -> Tablescanon t1 (cost=0.35rows=1)

4.总结

hash join 算法的出现对 join 语句的性能大幅提升,MySQL 8.0.20 后,对 hash join 的使用又做了进一步的优化,使用更加便捷。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/10/31 7:03:46

鲸剪 WhaleClip怎么样?5款视频下载深度对比

做短视频矩阵或二创时&#xff0c;最头疼的往往不是剪辑&#xff0c;而是找对标、下素材。很多创作者到处问「鲸剪 WhaleClip怎么样」&#xff0c;本质是想知道它的视频解析下载能力能不能替代零散的在线工具。鲸剪&#xff08;WhaleClip&#xff09;是一款面向短视频创作者与团…

作者头像 李华
网站建设 2026/10/31 7:02:14

Git 基础规范:小步提交、提交信息规范与常用命令

一、什么是小步频繁提交&#xff1f; 小步频繁提交&#xff1a;把一个比较大的开发需求、大功能&#xff0c;拆分成一个个很小、能够独立验证的子任务&#xff0c;每完成一个小任务&#xff0c;就及时提交一次代码。 举个例子&#xff1a;做登录页&#xff0c;不要等页面布局、…

作者头像 李华
网站建设 2026/10/31 7:01:24

AI连续三轮测试全对,第四轮为何仍出错?Anthropic官方案例拆解

同一组题连续跑了三遍&#xff0c;答案全部正确&#xff0c;能不能把新配置留下来&#xff1f;Anthropic的《Tokenomics on AWS》官方课给出了一个反例&#xff1a;前三轮通过&#xff0c;最终复测却只对了9题&#xff0c;讲者按事先约定撤回了变更。这个案例说明&#xff0c;检…

作者头像 李华
网站建设 2026/10/31 7:01:22

2026 夸克网盘批量转存与目录整理:少踩坑的实操清单

2026 夸克网盘批量转存与目录整理&#xff1a;少踩坑的实操清单 网盘文件一多&#xff0c;最常见的不是「传不上去」&#xff0c;而是转存后找不到、目录越建越乱、分享链失效不知道从哪修。下面按「转存 → 命名 → 归档 → 抽检」给一套可重复的流程&#xff0c;偏实操&#…

作者头像 李华
网站建设 2026/10/31 7:00:39

02.信号上升时间与带宽的关系

回顾任务1&#xff0c;方波含有很多频率成分&#xff0c;可以用很多频率的信号合成方波&#xff1b;信号的高频分量越多&#xff0c;他的上升时间越短&#xff0c;上升约陡峭。那么&#xff0c;改变已有信号的频谱&#xff0c;它的上升时间会发生什么变化&#xff1f;按照01的结…

作者头像 李华