改造pg的hashjoin形式为Symmetric Hash Join

1,319 阅读4分钟

一:背景

最近在做数据库内核原理的实验二的作业的时候一开始看pg代码遇到勒巨大的困难。所以在完成该作业之后希望能够将写作业的时候的经验记录下来,希望能给后面的人给带来一点作业启示。

1.1 要求如下:

将pg中使用到的hybrid hashjoin算法切换为Symmetric Hash Join。 image.png

1.2 实验环境:

二:从hash算法(hybrid_hash和symmetric_hash Join)形式了解pg的hash过程

对于pg处理hash过程而言分为两个阶段:

  • 构建阶段: 构建hash表
  • 探查阶段: 每次都去探查构建出来的hash表看有没有满足条件的行数据

2.1 构建角度:

我们如果想要将pg自带的hybrid_hashjoin修改为Symmetric Hash Join。 就需要先了解Symmetric Hash Join算法是如何处理inner数据和outer数据进行适配的。
这是hybrid hashjoin的构建图 image.png 这是Symmetric Hash Join的构建图 image.png
可以发现对于hybrid hashjoin而言它只会为inner_table构建一个hash_table而对于Symmetric Hash Join而言它会为inner_table和outer_table分别构建一个hash_table,所以最后会有两个hash_table。

2.2 探查搜索角度

hybrid_hash_join的探查方式 对于hybrid_hash_join而言它是采用先构建inner_hash表之后再去用outer_tuple去探查inner_hash表中是否有满足条件的数据。

symmetric_hash_join的探查方式 而对于symmetric_hash_join它是采用边构建边探查的形式去寻找匹配的数据的。 流程如下:

  • 从内部关系中读取一个元组,并使用内部关系的哈希函数将其插入到内部关系的哈希表中。然后,使用新元组来探测外部关系的哈希表是否匹配。探测时使用外部关系的哈希函数。
  • 当用内部元组探测没有更多匹配时,从外部关系中读取一个元组。使用外部关系的哈希函数将其插入到外部关系的哈希表中。然后,使用外部元组来探测内部关系的哈希表是否匹配,计算哈希值时使用内部表的哈希函数。
  • 持续执行上述两个操作。直到当外部关系读取完之后,继续一直读取内部关系。同理当内部关系读取完成之后继续一直读取外部关系

三:梳理改造点

3.1 修改配置项

  1. 要求测试的时候只使用hashjoin的形式而不使用nest_loop或者merge_join的形式,所以我们需要在 postgresql.conf这一个文件中配置一下关闭这两种join方法。 image.png

  2. 关闭多batch模式 由于在hybrid_hash_join模式中,是使用多个批次分批来处理元组的,但是在本实验中可以假设两个hash表都适合内存。 所以我们需要修改这一个多batch模式。

image.png

3.2 修改实现逻辑项

3.2.1 修改 createplan.c

该文件主要做的事情就是把路径树转换为计划树,并且整理筛选一些数据段。 之前只是对innerplan做了转换,这次要增加对 outerplan也进行转换。

image.png

image.png

3.2.2 修改 execnodes.h

文件包含 HashJoinState 结构,该结构用于执行过程中维护哈希连接的状态。 修改这一个文件,源文件中只对inner的状态进行了管理,这次要增加对outer的状态管理和outer_hash_table的管理。

image.png

3.2.3 修改 nodeHash.c

该文件主要是为了构建与维护哈希表
之前该文件的并没有实现流水线的哈希表构建,所以我们要在 ExecHash 中进行补充实现。 image.png 再而我们需要修改之前探查哈希表找匹配值的代码:

image.png

这次我们需要增加一下从内部表找匹配值和从外部表中找匹配值得代码

image.png

3.2.4 修改 nodeHash.h

文件包含 nodeHash.c 的函数原型。 在这里我们增加一下 ExecScanHashBucket_probeouter, ExecScanHashBucket_probeinner的原型(扫描外表,扫描内表) image.png

3.2.5 修改 nodeHashjoin.c

该文件主要负责实现哈希连接运算,判断什么值需要连接返回
在这里需要修改三个函数

  • ExecHashJoinImpl函数中进行节点连接返回(判断连接)
  • ExecInitHashJoin函数中进行连接状态初始化操作
  • ExecEndHashJoin函数中进行连接状态销毁操作 原实现是在ExecHashJoinImpl函数中进行连接返回的。 在该函数中使用状态机进行状态管理来执行。 image.png 于是在这里我们需要去修改它的状态机机制去做连接判断。 image.png 具体实现可看 Comparing 8ddadc3..9efe41f · jomeswang/pg-Symmetric-Hash-Join (github.com)

ExecInitHashJoin函数中主要是添加了一些状态的初始化 image.png

ExecInitHashJoin函数中主要是添加了一些状态的销毁

image.png

总结

好勒,如果你能够看到这里,说明你对这一个作业的完成有了一个更加清晰的认识了,接下来就需要你继续去完善自己的想法部分了。这一个作业微微复杂,希望大家都能够开开心心的完成,并且能够从中学习到pg的一些设计思想与模型。