我的编程空间,编程开发者的网络收藏夹
学习永远不晚

技术分享 | Hash join in MySQL 8

短信预约 信息系统项目管理师 报名、考试、查分时间动态提醒
省份

北京

  • 北京
  • 上海
  • 天津
  • 重庆
  • 河北
  • 山东
  • 辽宁
  • 黑龙江
  • 吉林
  • 甘肃
  • 青海
  • 河南
  • 江苏
  • 湖北
  • 湖南
  • 江西
  • 浙江
  • 广东
  • 云南
  • 福建
  • 海南
  • 山西
  • 四川
  • 陕西
  • 贵州
  • 安徽
  • 广西
  • 内蒙
  • 西藏
  • 新疆
  • 宁夏
  • 兵团
手机号立即预约

请填写图片验证码后获取短信验证码

看不清楚,换张图片

免费获取短信验证码

技术分享 | Hash join in MySQL 8

作者:Erik Frøseth 翻译:管长龙 原文:https://mysqlserverteam.com/hash-join-in-mysql-8/

长期以来,在 MySQL 中执行 join 查询的只是嵌套循环算法的变体。随着 MySQL 8.0.18 的发布,现在可以使用 Hash join 执行 joins。这篇博客文章将介绍它的工作原理,使用时间以及在性能方面与 MySQL 中旧的 join 算法的比较。

什么是 Hash join?

Hash join 是一种执行 join 的方式,其中哈希表用于查找两个输入之间的匹配行(一个输入是一个或多个表)。它通常比嵌套循环 join 更有效,特别是如果其中一个输入可以容纳在内存中时。为了查看其工作方式,我们将使用以下查询作为示例:

SELECT
  given_name, country_name
FROM
  persons JOIN countries ON persons.country_id = countries.country_id;

① 构建阶段

通常 Hash join 分为两个阶段:构建阶段和探测阶段。

在构建阶段,服务使用联接属性作为哈希表键,构建一个内存中的哈希表,其中存储来自输入之一的行。此输入也称为构建输入,让我们假设将 countries 指定为构建输入。理想情况下,服务将选择两个输入中较小的一个作为构建输入(以字节为单位,而不是行数)。

由于 countries.country_id 是属于构建输入的联接条件,因此将其用作哈希表中的键。一旦所有行都存储在哈希表中,就完成了构建阶段。

② 探测阶段

在探测阶段,服务开始从探测输入(在我们的示例中为 persons )读取行。 对于每一行,服务都会使用 persons.country_id 中的值作为查找键来探测哈希表是否匹配行。对于每个匹配项,将向客户端发送一个合并的行。最后,服务仅扫描每个输入一次,使用恒定时间查找来查找两个输入之间的匹配行。

假设服务可以将整个构建输入存储在内存中,则此方法非常有效。可用的内存量由系统变量 join_buffer_size 控制,可以在运行时进行调整。但是,如果构建输入大于可用内存,会发生什么?我们溢出到磁盘上!

③ 溢出到磁盘

在构建阶段内存已满时,服务器会将其余的构建输入写出到磁盘上的多个块文件中。服务器试图设置块的数量,以使最大的块恰好适合内存(我们很快就会知道为什么),但每次输入的块文件个数严格上限是 128。通过计算 join 属性的哈希值来确定将行写入哪个块文件。请注意,在图示中,使用了与内存构建阶段中使用的哈希函数不同的哈希函数。稍后我们将了解原因。

在探测阶段,服务器会探测哈希表中的匹配行,就像所有内容都适合内存一样。但是除此之外,一行还可能与写入磁盘的构建输入中的一行匹配。因此,来自探测输入的每一行也被写入一组块文件。使用将构建输入写入磁盘时使用的哈希函数和公式确定将行写入哪个块文件。这样,我们可以确定两个输入之间的匹配行将位于同一对块文件中。

探测阶段完成后,我们开始从磁盘读取块文件。通常,服务器使用第一组块文件作为构建和探测输入来执行构建和探测阶段。我们将构建输入中的第一个块文件加载到内存中的哈希表中。这解释了为什么我们希望最大的块恰好适合内存。如果块文件太大,我们需要将其分成更小的块。加载构建块后,我们从探测输入读取相应的块文件,并在哈希表中探测匹配项,就像所有内容都适合内存一样。处理完第一对块文件后,我们将移至下一对块文件,继续进行直到所有对块文件都已处理为止。

您现在可能已经猜到了为什么在将行划分为块文件并将行写入哈希表时,为什么应该使用两个不同的哈希函数。如果我们要对两个操作使用相同的哈希函数,则在将构建块文件加载到哈希表中时,将得到一个非常糟糕的哈希表,因为同一块文件中的所有行都将哈希成相同的值。

这么赞,我该如何使用?

Hash join 默认情况下处于启用状态,因此无需执行任何操作即可使用哈希联接。值得注意的是,Hash join 建立在新的迭代器执行器上,这意味着您必须使用 EXPLAIN FORMAT = tree 来查看是否将使用 Hash join:

mysql> EXPLAIN FORMAT=tree
    -> SELECT
    ->   given_name, country_name
    -> FROM
    ->   persons JOIN countries ON persons.country_id = countries.country_id;
+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| EXPLAIN                                                                                                                                                                                                 |
+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| -> Inner hash join (countries.country_id = persons.country_id)  (cost=0.70 rows=1)
    -> Table scan on countries  (cost=0.35 rows=1)
    -> Hash
        -> Table scan on persons  (cost=0.35 rows=1)     |
+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
1 row in set (0.01 sec)

通常,如果使用一个或多个等联接条件将表联接在一起,并且联接条件没有索引,则将使用 Hash join。如果索引可用,则 MySQL 倾向于使用带有索引查找的嵌套循环。

我们引入了一个新的优化器开关,使您可以对任何查询禁用 Hash join:

mysql> SET optimizer_switch="hash_join=off";
Query OK, 0 rows affected (0.00 sec)

mysql> EXPLAIN FORMAT=tree
    -> SELECT
    ->   given_name, country_name
    -> FROM
    ->   persons JOIN countries ON persons.country_id = countries.country_id;
+----------------------------------------+
| EXPLAIN                                |
+----------------------------------------+
|										 |
+----------------------------------------+
1 row in set (0.00 sec)

禁用 Hash join 后,MySQL 将退回到块嵌套循环,从而使用旧的执行程序(迭代器执行程序不支持块嵌套循环)。此开关使比较 Hash join 和块嵌套循环的性能变得容易。

如果由于构建输入太大而导致无法容纳在内存中并使用磁盘,则可以增加连接缓冲区的大小。与块嵌套循环相反,Hash join 将递增地分配内存,这意味着它将永远不会使用超出其需求的内存。因此,使用 Hash join 连接时,使用较大的连接缓冲区大小更安全。

性能数据!

我们做了一些基准测试以查看 Hash join 与块嵌套循环相比如何,结果看起来像这样:

您可以在此处查看结果的演示。首先,我必须提到在此测试中我们确实禁用了所有索引。这是为了使优化器使用块嵌套循环和 Hash join 来创建执行计划,因此您在此处看到的数字不会显示出对 DBT-3 执行时间的总体改进。进行此测试是为了突出块嵌套循环和 Hash join 之间的区别。但是我们可以看到,在所有使用 Hash join 的查询中,Hash join 显然都优于块嵌套循环。调整了缓冲池的大小,以便所有数据都在内存中,并且连接缓冲区的大小与默认值(约 250kB)保持不变。显着的改进是由于以下事实:每次输入 Hash join 仅扫描一次,并且它使用恒定时间查找来查找两个表之间的匹配行。

遗憾的是,当前 Hash join 的实现存在一些限制:

MySQL 仅支持内部 Hash join,这意味着反,半和外部联接仍使用块嵌套循环执行。 优化器/计划器使用块嵌套循环执行连接。但应该更频繁地使用 Hash join。 我们希望将来消除这两个限制,但是即使存在这两个限制,哈希联接也应使您的查询运行更快。

免责声明:

① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。

② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341

技术分享 | Hash join in MySQL 8

下载Word文档到电脑,方便收藏和打印~

下载Word文档

猜你喜欢

技术分享 | Hash join in MySQL 8

作者:Erik Frøseth翻译:管长龙原文:https://mysqlserverteam.com/hash-join-in-mysql-8/长期以来,在 MySQL 中执行 join 查询的只是嵌套循环算法的变体。随着 MySQL 8.0.18 的发布,
技术分享 | Hash join in MySQL 8
2020-01-17

技术分享 | MySQL 优化:JOIN 优化实践

近期刚好学习了丁奇老师的《MySQL 实战 45 讲》中的 join 优化相关知识,又刚刚好碰上了一个非常切合的 join 查询需要优化,分析过程有些曲折,记录下来留作笔记。问题 SQL 描述问题 SQL 和执行计划是这样的:explain SELECT
技术分享 | MySQL 优化:JOIN 优化实践
2015-01-09

技术分享 | Jump Consistent Hash 原理解析(上篇)

之前爱可生开源社区公众号发表了dble 沿用 jumpstringhash,移除 Mycat 一致性 hash 原因解析, 阐述了跳跃法相对环割法的性能优势。很多读者表示对其中"跳跃法的原理"不是很理解,本文就来详细阐述一下。一致性哈希首先,我们的需求是,将数
技术分享 | Jump Consistent Hash 原理解析(上篇)
2021-01-24

技术分享 | MySQL Test 初探

作者:雷霞爱可生测试团队负责人,专注于 MySQL 相关的测试工作。​本文来源:原创投稿*爱可生开源社区出品,原创内容未经授权不得随意使用,转载请联系小编并注明来源。什么是 Mysql Test?Mysql Test 是 MySQL 发行版本中集成 all-i
技术分享 | MySQL Test 初探
2014-06-10

技术分享 | 回顾 MySQL 的 MTS

作者:洪斌爱可生南区负责人兼技术服务总监,MySQL ACE,擅长数据库架构规划、故障诊断、性能优化分析,实践经验丰富,帮助各行业客户解决 MySQL 技术问题,为金融、运营商、互联网等行业客户提供 MySQL 整体解决方案。本文来源:转载自公众号-玩转My
技术分享 | 回顾 MySQL 的 MTS
2021-03-19

技术分享 | MySQL 子查询优化

作者:胡呈清爱可生 DBA 团队成员,擅长故障分析、性能优化,个人博客:https://www.jianshu.com/u/a95ec11f67a8,欢迎讨论。本文来源:原创投稿*爱可生开源社区出品,原创内容未经授权不得随意使用,转载请联系小编并注明来源。有这
技术分享 | MySQL 子查询优化
2016-07-07

技术分享 | MySQL TEXT 字段的限制

一、背景说明项目中有一个数据交换的场景,由于使用了很多个 varchar(1000)、varchar(2000),导致在创建表的时候,MySQL 提示:ERROR 1118 (42000): Row size too large (> 8126). Chang
技术分享 | MySQL TEXT 字段的限制
2020-11-24

技术分享 | MySQL 多源复制场景分析

作者:杨涛涛今天有客户问起:如何汇总多台 MySQL 数据到一台上? 我回答:可以尝试下 MySQL 的多源复制。我们知道 MySQL 单主一从,单主多从,或者级联的主从架构我们都见的很多了。但是多主一从这种使用场景比较少,比如图1:这种架构一般用在以下三类场
技术分享 | MySQL 多源复制场景分析
2019-10-02

技术分享 | MariaDB 10.1.9 迁移到 MySQL 5.7.25

作者:秦广飞爱可生 DBA 团队成员,负责项目日常问题处理及公司平台问题排查,对数据库有兴趣,对技术有想法。一入 IT 深似海,从此节操是路人。本文来源:原创投稿*爱可生开源社区出品,原创内容未经授权不得随意使用,转载请联系小编并注明来源。背景客户环境数据库目
技术分享 | MariaDB 10.1.9 迁移到 MySQL 5.7.25
2015-04-25

技术分享 | MySQL 监控利器之 Pt-Stalk

一、概述之前在社区发了一篇故障分析 | 有效解决 MySQL 行锁等待超时问题文档,主要介绍了下行锁超时的监控方法,下方评论中有人提到了 pt-stalk 工具也可以监控行锁超时,因为个人没怎么用过这个工具,所以下意识的就去 google 了一下。因为没找到有
技术分享 | MySQL 监控利器之 Pt-Stalk
2018-05-02

技术分享 | 如何编写 MySQL Shell 插件

作者:洪斌爱可生南区负责人兼技术服务总监,MySQL  ACE,擅长数据库架构规划、故障诊断、性能优化分析,实践经验丰富,帮助各行业客户解决 MySQL 技术问题,为金融、运营商、互联网等行业客户提供 MySQL 整体解决方案。本文来源:转载自公众号-玩转My
技术分享 | 如何编写 MySQL Shell 插件
2016-08-09

技术分享 | 用好 MySQL 的 MRR 优化器

作者:蒋乐兴MySQL DBA,擅长 python 和 SQL,目前维护着 github 的两个开源项目:mysqltools 、dbmc 以及独立博客:https://www.sqlpy.com。本文来源:原创投稿*爱可生开源社区出品,原创内容未经授权不得随
技术分享 | 用好 MySQL 的 MRR 优化器
2014-12-31

技术分享 | MySQL 数据库如何改名?

作者:杨涛涛资深数据库专家,专研 MySQL 十余年。擅长 MySQL、PostgreSQL、MongoDB 等开源数据库相关的备份恢复、SQL 调优、监控运维、高可用架构设计等。目前任职于爱可生,为各大运营商及银行金融企业提供 MySQL 相关技术支持、My
技术分享 | MySQL 数据库如何改名?
2020-04-24

技术分享 | 安全地无密码登录 MySQL

作者:丹尼尔·古斯曼布尔戈斯翻译:管长龙原文:https://www.percona.com/blog/2019/11/01/use-mysql-without-a-password/有人说最好的密码就是你不用记忆的。auth_socket 插件和 Maria
技术分享 | 安全地无密码登录 MySQL
2018-01-05

PostgreSQL技术分享公开课:备份恢复与Point-in-Time Recovery(PITR)

1、PostgreSQL 12.2 备份恢复 时间:2020-03-14 20:00-21:00 内容介绍: 1.pg_dump备份以及进行选择性恢复 2.pg_dumpall备份与恢复 3.COPY备份与恢复 4.pg_basebackup与恢复 5.PG快
PostgreSQL技术分享公开课:备份恢复与Point-in-Time Recovery(PITR)
2014-07-30

技术分享 | MySQL:从库出现 system lock 的原因

作者:高鹏(网名八怪)文章末尾有他著作的《深入理解 MySQL 主从原理 32 讲》,深入透彻理解 MySQL 主从,GTID 相关技术知识。本文来源:转载自公众号-老叶茶馆*爱可生开源社区出品,原创内容未经授权不得随意使用,转载请联系小编并注明来源。本文为笔
技术分享 | MySQL:从库出现 system lock 的原因
2021-01-03

技术分享 | mysql show processlist Time 为负数的思考

作者:高鹏文章末尾有他著作的《深入理解 MySQL 主从原理 32 讲》,深入透彻理解 MySQL 主从,GTID 相关技术知识。一、问题来源这是一个朋友问我的一个问题,问题如下,在 MTS 中 Worker 线程看到 Time 为负数是怎么回事,如下:二、关
技术分享 | mysql show processlist Time 为负数的思考
2020-10-10

技术分享 | MySQL 的 join_buffer_size 在内连接上的应用

作者:杨涛涛本文详细介绍了 MySQL 参数 join_buffer_size 在 INNER JOIN 场景的使用,OUTER JOIN 不包含。在讨论这个 BUFFER 之前,我们先了解下 MySQL 的 INNER JOIN 分类。如果按照检索的性能方式
2016-04-15

技术分享 | MySQL 主机该如何配置 fs.aio-max-nr

MySQL 默认是启用 innodb_use_native_aio,使用异步 IO 操作,MySQL 启动时所需 aio slot 若超过系统当前 fs.aio-max-nr 设置,则无法启动报错 InnoDB: io_setup() failed with
技术分享 | MySQL 主机该如何配置 fs.aio-max-nr
2017-10-18

技术分享 | MySQL 8.0:字符集从 utf8 转换成 utf8mb4

作者:胡呈清整理 MySQL 8.0 文档时发现一个变更:默认字符集由 latin1 变为 utf8mb4。想起以前整理过字符集转换文档,升级到 MySQL 8.0 后大概率会有字符集转换的需求,在此正好分享一下。当时的需求背景是:部分系统使用的字符集是 ut
2016-03-25

编程热搜

目录