Mysql 各种hash join算法讲解

hash join的概述

提到hash join之前自然得说Nest loop join,以两个表的关联为例,它其实是个双层循环,先遍历外层的表(n条),再拿每次对应的值去匹配、循环遍历内部的表(M条)。这样显然会有M*n的计算复杂度。如果能将外部表先装载到内存,然后再做内部表的匹配、遍历,计算的复杂度就会大大降低,这就是hash join的思想。

本文继续介绍hash join的其它几个算法On-Disk Hash Join、Grace Hash Join、Hybrid hash join。其中In Memory Join classic hash join的介绍见:

Mysql 优化器内部JOIN算法hash join Nestloopjoin及classic hash join CHJ过程详解_数据科学汇集-CSDN博客Mysql hash join之classic hash join CHJ过程详解hash join的历史优化器里的hash join算法在SQL Server、Oracle、postgress等数据库早已实现,而Mysql在8.0.18之后才支持。在8.0.18之前mysql只支持嵌套循环关联(nested loop join),这其中最简单就是简易嵌套循环关联simple nestloop join,随后mysql做了改进进而支持block nestloop join, index nestlohttps://shenliang.blog.csdn.net/article/details/120498088

On-Disk Hash Join

CHJ算法在构建表时的内存大小可通过参数join_buffer_size来设置,但因为需要把整个表都装到内存里,所以这种方法遇到比较大的表时就显得捉襟见肘。不过也不是没有方法去规避,我们按照如下的策略方向做改进(分批执行的思想,记作):

1 在构建哈希表时读取尽量多的内容到内存。

2 运行探测过程时读取整个探测的输入(即对应1里的内容)。

3 擦除(清空)内存里的哈希表。

4 循环步骤1里执行直至遍历完构建过程里的数据。

不过因为需要多次读取构建的输入(即构建表)还是有风险且有成本的,假设构建表被分成了n份,那么在匹配探测表时将会扫描n次。这时借助磁盘分区执行的方法on-Disk Hash Join就应运而生了。详细步骤见下:

Step1:把构建表和探测表在磁盘上分成若干小区(块),这里分配的原则是每个小区(块)能全部装载到内存里,而构建表的确定和classic hash join算法类似(一般优先选择小表)。

Step2:当所有的记录都已经分区(块)到磁盘上的小文件后,开始遍历分区(块),进入构建阶段即将第一个分区通过函数函数装载到内存里形成哈希表,然后在探测阶段扫描第一个分区(块),该分区(块)对应构建阶段里分区。因为在生成分区信息时构建表和探测表用相同的哈希函数,所以在探测阶段进行匹配时很容易找到对应的分区信息。

Step3:当第一个分区(块)处理完了之后清空内存里的哈希表,然后把第二个分区文件装载到构建表,在探测过程用第二个分区的信息匹配探测表,依次类推直至所有的分区(块)都遍历完。

通过对On-Disk Hash Join的执行过程进行分析,我们不难发现该算法会在构建过程读取IO两次、探测过程写一次IO。这与开头里介绍的hash join改善算法(n次IO扫描探测表)已经有较大的进步。

构建表分区

探测表分区

构建探测两过程​​​​​​

1 in-memory hash join和on-disk hash join算法都是用的msxxHash64作为哈希函数,它是在提供高质量的哈希值的同时又能保证快速(减少哈希冲突的数量)。

2 如果有一个数据集倾斜的结果集会导致构建表里的一个分区(块)不能填入内存,那么hash join算法会按照如下的逻辑处理:

1 读取尽量多的分区(块)到内存。

2 在整个探测阶段读取探测分区。

3 清空内存里的哈希表。

4 调转到步骤1直至构建分区里没有数据。

Grace Hash Join

当连接缓存大小(join buffer size)不足时,mysql会先分片再按照classic hash join的方式处理(见On-Disk Hash Join里的注2)。但在极端情况,如果数据分布不均匀,有大量数据经过哈希后分布到一个桶内,这将导致分片后的连接缓存大小仍然不足。碰到这种情况oracle的grace hash join算法则会继续拆分直至有足够的内存可以存放哈希表,当然如果在关联条件相同的情况下不论再怎么哈希还是不能拆分时grace hash join也退化为和像mysql一样先分片再classic hash join的方式处理方式。

Hybrid hash join

如果缓存足够多的分片数据会尽量缓存,那么就不必像GraceHash那样将所有分片都先读进内存,再写到外存,最后再读进内存进行build过程,这就是Grace Hash Join算法的核心,即在内存相对于分片比较充裕的情况下可以减少磁盘的读写IO。目前Oceanbase的HashJoin采用的是这种join方式。

hash join的伪代码

result = []
join_buffer = []
partitions = 0
on_disk = False
for country_row in country:if country_row.Continent == 'Asia':hash = xxHash64(country_row.Code)if not on_disk:join_buffer.append(hash)if is_full(join_buffer):# Create partitions on diskon_disk = Truepartitions = write_buffer_to_disk(join_buffer)join_buffer = []elsewrite_hash_to_disk(hash)if not on_disk:for city_row in city:hash = xxHash64(city_row.CountryCode)if hash in join_buffer:country_row = get_row(hash)city_row = get_row(hash)result.append(join_rows(country_row, city_row))else:for city_row in city:hash = xxHash64(city_row.CountryCode)write_hash_to_disk(hash)
for partition in range(partitions):join_buffer = load_build_from_disk(partition)for hash in load_hash_from_disk(partition):if hash in join_buffer:country_row = get_row(hash)city_row = get_row(hash)result.append(join_rows(country_row, city_row))
join_buffer = []

代码简介

从country表里读取每一行并计算code字段对应的哈希值并存储在连接缓存内(join buffer)。如果连接缓存满了则走on-disk算法并哈希后的缓存写到外部磁盘。也正是在此时分区的个数确定,然后对country表剩下的数据继续哈希。

对于in-memory的算法只需要通过循环比较city和缓存里的哈希值即可,而对于on-disk算法哈希的city表会被首先计算并存放在磁盘然后再通过分区一个个的匹配。

参考:

MySQL :: WL#2241: Hash join

New features of MySQL 8.0 hash join | Develop Paper

Mysql 优化器内部JOIN算法hash join On-Disk Hash Join Grace Hash Join Hybrid hash join过程详解相关推荐

  1. Mysql 优化器内部JOIN算法hash join Nestloopjoin及classic hash join CHJ过程详解

    Mysql hash join之classic hash join CHJ过程详解 hash join的历史 优化器里的hash join算法在SQL Server.Oracle.postgress等 ...

  2. MySQL优化器如何预估查询成本

    MySQL有哪些查询成本 MySQL 执行一个查询可以有不同的执行方案.在我们开发过程中,所有写过的sql语句都会丢给MySQL端的优化器.由优化器判断并选择其中成本最低,或者说代价最低的那种方案去真 ...

  3. MySQL优化器_MySQL查询优化器

    MySQL优化器 MySQL架构图 讲到MySQL,就绕不开他的架构图.MySQL是一个经典的C/S架构.服务器这边分两层:第一层是Server层,第二层是存储引擎.Server层处理主要的业务操作流 ...

  4. MySQL优化器:index merge介绍

    在MySQL官方手册上,关于index merge的介绍非常非常少.甚至还有不少误导的地方,这次把5.1版本关于此类优化处理的代码细看了一遍,以案例的方式介绍了各种实用index merge访问类型的 ...

  5. mysql not in优化_98%的人不知道的MySQL优化器原理

    ​| 作者 梁东阳,数据库研发中心数据库内核工程师,负责腾讯云MySQL的内核开发. 在日常运维中,相信不少人都收藏了很多关于查询优化的方法论和小技巧,但是仔细想想,你真的了解这些优化背后的原理吗? ...

  6. MySQL优化器选错索引情况

    MySQL优化器选错索引情况 1. 优化器选错索引 2. 优化器的逻辑 3. 索引选择异常和处理 1. 优化器选错索引 之前MySQL架构以及执行sql查询语句介绍过MySQL优化器可以帮助我们优化s ...

  7. MySQL 优化器原来是这样工作的

    文章目录 优化器概述 逻辑转换 基于成本的优化 控制优化程度 设置成本常量 数据字典与统计信息 控制优化行为 优化器和索引提示 总结 大家好,我是只谈技术不剪发的 Tony 老师.我们在 MySQL ...

  8. mysql优化器怎么选择索引,为什么MySQL查询优化器会选择聚集主索引上的二级索引?...

    为什么Mysql优化器在执行'select * from lookup'而没有order by子句时选择二级索引. 它只是一个侥幸,或者这是一个幕后优化,假设你添加了一个二级索引,它比主键更重要. 我 ...

  9. mysql优化器放弃索引场景,MYSQL索引优化(索引失效场景)

    学习mysql是作为一名Java工程师必不可少的事情,但是我们只认识mysql的增删查改建表等等的sql语句其实远远不够的,对于进阶mysql来说,索引是一个很重要的部分.下面我们就来说一下在mysq ...

最新文章

  1. 初学者如何搭建一个自己专属的电子实验室?
  2. xend: No such file or directory. Is xend running? 问题
  3. PHP微信开发框架LaneWeChat框架简介
  4. for循环里radio多选_Max里的for循环
  5. 深入浅出学Hive:Hive内建操作符与函数开发
  6. pcb只开窗不镀锡_案例图解射频PCB设计要点
  7. 指针和引用的相同与不同
  8. 直觉模糊有计算机知识嘛,多源直觉模糊信息系统的知识获取方法
  9. [css]通过transform缩放邮件客户端h5页面
  10. 点云边界提取方法总结
  11. JavaScript模态框实现
  12. python 设备ArtNetToDMX512的协议测试
  13. 中国互联网大人物直播简史
  14. 使用VBA让Word或Excel文档窗口置顶
  15. 结绳计数——最原始的备忘录
  16. Android - 城市/单项/国家区号选择器基础使用 及 使用国际区号json文件
  17. C语言小程序实现输出国际象棋棋盘
  18. 七月上伴奏计算机按键,数字化音乐专业教室配备方案(7页)-原创力文档
  19. 日有所思(7)——电拖疑问
  20. Vue响应式原理(看这一篇就够了)

热门文章

  1. boost::detail::atomic_count相关的测试程序
  2. boost::adaptors::copied相关的测试程序
  3. boost::histogram::histogram::fill用法的测试程序
  4. boost::gil::derived_view_type用法的测试程序
  5. boost::geometry::topological_dimension用法的测试程序
  6. Boost:boost::bimaps::vector_of的测试程序
  7. DCMTK:OFnumeric_limits的单元测试
  8. DCMTK:测试CT Table Dynamics FG类
  9. DCMTK:表示增强型CT对象的类
  10. OpenCV 拉普拉斯算子Laplace Operator