Reading Note(4)——面向关系型数据库的哈希连接加速器

0.Briefly Speaking

这是一篇比较短的文章(文章链接),主要讲述的是如何使用FPGA来加速数据库系统中等值连接(equi-join)中的一种算法——哈希连接

数据库在完成连接操作时一般会有三种算法作为候选:hashmerge-sortnested loop,有关这几种算法之间的工作方式可以自行检索。本文做的工作就是面向hash连接算法提出了一种基于FPGA的硬件加速器,来提升数据库连接操作的性能。

1. INTRODUCTION

这部分首先介绍了连接操作的重要性,以及连接操作的性质:连接操作是一种资源密集型任务,也就是说开展连接操作需要耗费大量的CPU计算资源,所以现在越来越倾向于将连接操作使用硬件加速来完成。

随后这部分内容简要回顾了三种连接算法的工作过程,并指出影响哈希连接性能的主要原因就是存在hash碰撞,从而造成了不良的数据分布

1.设计了一种通用的FPGA加速哈希连接体系结构,用于解决哈希冲突,这种体系结构不需要同步重新处理数据

2.使用了一种基于布谷鸟哈希的方式来提升哈希表的内存利用率(布谷鸟哈希的简介),并动用了一小部分SRAM来挖掘算法中的并行性以提升吞吐率。

3.打破了原有存在的必须在哈希函数的鲁棒性和哈希连接性能之间权衡的窘境。

2.PREVIOUS WORKS

这部分回顾了相关工作,并简单分析了它们的不足,以及这篇工作的出发点。

3.PROPOSED JOIN ARCHITECTURE

这部分简单对用在本文中的布谷鸟哈希做了简单介绍,并对提出的专用于连接的加速器架构进行了概览。本部分约定如下假设:

  1. 假设数据表逐行流入FPGA,第一张表和第二张表分别拥有 N N N M M M行,其中 N < M N \lt M N<M
  2. 元组(完整记录的一部分)以 { r i d , k e y } \{rid, key\} {rid,key}的形式流入FPGA,其中 r i d rid rid用于单独的标注一行, k e y key key则是用于连接的属性。
  3. 连接结果的形式为 { r i d 1 , r i d 2 , k e y } \{rid1, rid2, key\} {rid1,rid2,key},在第二个表格流入FPGA时产生结果。

3.1 Cuckoo Hash

这部分首先对布谷鸟哈希做了一个简单的介绍,并举了一个简单的例子。
这里不再对原文进行翻译,而是援引来自Wikipedia上的介绍:

Cuckoo Hashing是计算机编程中的一个方案,用于解决表中散列函数值的哈希碰撞,具有最坏情况的常量查找时间。这个名字源于一些杜鹃的行为,杜鹃小鸟在孵化时将另一个鸡蛋推到巢中;类似地,将新密钥插入Cuckoo散列表中可以将较旧的密钥推向表格中的不同位置。

布谷鸟哈希其实就是同时使用两个hash函数来解决冲突,它的常见操作有如下几个:

  1. 查找(lookup)
    Reading Note(4)——面向关系型数据库的哈希连接加速器_第1张图片
    其实就是使用两个hash函数分别去查找两个位置,任何一个位置上找到了x都算作查找成功。
  2. 删除(delete)
    删除一定是在 O ( 1 ) O(1) O(1)时间内完成的,因为每一个key所在位置都是符合其hash映射的位置。
  3. 插入(insert)
    首先给出插入操作的伪代码描述Reading Note(4)——面向关系型数据库的哈希连接加速器_第2张图片
    大体过程就是如果要插入元素的x,其哈希值 h 1 ( x ) h_1(x) h1(x) h 2 ( x ) h_2(x) h2(x)所对应的桶(bucket)如果至少有一个为空,那么就直接插入。如果两个都非空,那么就随机选择一个较老的受害者项(victim item),将其踢出所在桶并为其重新寻找它的侯选位置进行插入,这个过程会一直循环到找到一个空的桶。如果无论如何也找不到一个新的桶(死循环),那么hash表将重构(rehash)。

最后给出论文中的举例,作为对布谷鸟哈希插入过程的一个理解。
Reading Note(4)——面向关系型数据库的哈希连接加速器_第3张图片

3.2 Hash Join Architecture

这一部分用来介绍本文提出的加速器架构。加速器的整体概览如下所示:

Reading Note(4)——面向关系型数据库的哈希连接加速器_第4张图片

  • 缓冲buffer用来缓解表项流入速度表项处理速度之间的不平衡。
  • 两个hash函数用来将表项映射到hash table的不同桶(buckets)
  • hash表的不同桶中含有4个槽,每个槽拥有三个成员 { s t a t u s , t a g , h e a d } \{status, tag, head\} {status,tag,head},其中 s t a t u s status status表示槽是否已经被使用, t a g tag tag用来指示另一个候选桶的编号, h e a d head head用来指示槽的第一个元组的入口。
  • 除此之外,每个桶中还有两个附加位用来在发生哈希碰撞时平衡链表长度。
  • 地址表(address table),存放的是 { r i d , k e y , p t r } \{rid, key, ptr\} {rid,key,ptr}三元组, r i d rid rid唯一标识了一行数据, k e y key key将要被用来与第二个表进行对比来确定连接, p t r ptr ptr则指向在同一个槽中冲突的下一个表项的rid。
  • 控制器(controller)运转着一个有限自动机,来控制构建阶段(build phase)和探测阶段(probe phase)的工作。
    Reading Note(4)——面向关系型数据库的哈希连接加速器_第5张图片

3.3 Build Phase

构建阶段加速器控制器主要完成的工作如下:
我们要做的事情就是将第一个表(小表)中的每一个元组插入到

  1. 查看 h 1 ( k e y n ) h_1({key_n}) h1(keyn)或者 h 2 ( k e y n ) h_2({key_n}) h2(keyn)对应的bucket是否有空闲的槽,如果有那么就可以插入并修改对应槽。如果没有空闲的槽可供插入,那么就去查找每一个槽的 t a g tag tag标签来查询候选bucket中是否存在空闲的槽。如果有空闲的槽,那么就将原先槽中存储的数据逐出到候选bucket的槽,新的数据放置到原先槽的位置。
  2. 如果要插入的桶和备选桶中都没有空闲的槽,那么这时候就要用到每个桶的两位附加位来决定这个新的元组应该被放在哪个地址表中。一旦确定了要插入的地址表,状态机就会循着这个槽对应的head指针一步步索引到链表的尾部,并将其插入,原先链表的最后一项的指针修改为新插入项的rid。

3.4 Probe Phase

这一部分就是将第二个表与第一个表进行匹配和连接的过程,控制器会将第二个表路由到正确的bucket,并行进行8个槽的搜索,每个槽内的操作就是将冲突链表中的每一项都与第二个表的元组进行逐一比较,一旦发现匹配,就立即导出连接结果。

4.EVALUATION

实验使用的平台是Xilinx Zynq UltraScale ZCU102,1个哈希表2个哈希函数,每个bucket有4个槽,12bit的哈希函数,16bit的地址指针,实验的结果如下所示:
Reading Note(4)——面向关系型数据库的哈希连接加速器_第6张图片
结论可以总结为:

  1. 随着输入表格尺寸的不断扩大,哈希表会逐渐趋于满载。满载情况下再增加输入表格尺寸,就会造成构建阶段和探测阶段的性能下降。但是,探测阶段的性能下降远远比构建阶段快的多。
  2. 随着匹配率的上升,可以看到吞吐率也会随之提升。在a)b)的设定中,匹配率固定在50%。
    Reading Note(4)——面向关系型数据库的哈希连接加速器_第7张图片
    相比于原先的工作,这篇工作提升了至少4.2x的并行哈希连接处理性能。

你可能感兴趣的:(ReadingNotes,fpga开发,系统架构,硬件架构)