当前位置:首页 >焦点 >CMU 15445 学习之Hash Table 接下来继续向上一层

CMU 15445 学习之Hash Table 接下来继续向上一层

2024-06-30 14:55:10 [百科] 来源:避面尹邢网

CMU 15445 学习之Hash Table

作者:roseduan 数据库 其他数据库 哈希表是学习一个高效的数据结构,大多时候能够在 O(1) 的学习情况下插入和查询数据,在数据库系统中,学习有很多地方都使用到了哈希表,学习例如前面提到的学习 page table,page directory,学习以及执行 sql 查询时一些用于 join 的学习临时数据结构。

前面的学习几篇文章已经将磁盘管理和内存 buffer pool 管理的内容都介绍完了,接下来继续向上一层,学习来介绍关于 access method 的学习内容。

图片

CMU 15445 学习之Hash Table 接下来继续向上一层

access method 主要是学习介绍一些数据结构,例如 Hash Table 和 Tree。学习这些数据结构可以用来做表的学习索引,以及一些在 sql 计算时的学习临时数据结构。

CMU 15445 学习之Hash Table 接下来继续向上一层

在设计和使用这些数据结构时,学习需要注意两个问题,一是数据的组织,怎样将数据组织在内存或者磁盘中,并且能够高效的访问;二是数据结构的并发访问问题,需要保证其在多线程环境下的数据安全。

CMU 15445 学习之Hash Table 接下来继续向上一层

今天先来看一下在数据库里面频繁被使用,以及数据结构中也会经常涉及到的哈希表。

Hash Table 概念

Hash Table 是一个无序的 key 到 value 的映射实现,它使用一个哈希函数计算数据存储到数组中(槽位)的位置,并且平均情况下,能够在 O(1) 的时间内访问元素。

如下图所示,我们通过一个 hash 函数,计算 key 在数组中中的下标,然后 key 对应了具体的 value。当查找数据时,也需要计算哈希值,然后定位到 key 所在的位置进行取值。

图片

Hash 函数

从前面的描述中可以看到,哈希函数在 Hash Table 中的作用至关重要。

哈希函数可以将任意类型的 key 转换为一个代表这个 key 的整数,在理想的情况下,我们希望任意不同的 key 经过哈希函数计算出来的值都是不同的,但在实际的哈希函数实现中,这几乎是不太可能的。

如果不同的 key 通过哈希函数计算出来的值是一样的,这种情况叫做哈希冲突(conflict),又叫哈希碰撞(collision)。

一般来说,计算哈希的速度越快,哈希冲突的概率越大,反之则越低,这就需要在实际设计时进行权衡。

数据库中常见的哈希函数实现有下列这几种:

  • crc64:https://create.stephan-brumme.com/crc32/
  • MurmurHash:https://github.com/aappleby/smhasher
  • Google CityHash:https://github.com/google/cityhash
  • Facebook XXHash:http://cyan4973.github.io/xxHash/
  • Google FarmHash:https://github.com/google/farmhash

Static Hash Scheme

接下来了解一下几种静态哈希的实现方式,所谓静态,一般是指哈希表的容量大小是固定的,所以能够存储数据的上限也是确定的,实际使用并不多,可以做参考。

Linear Probe Hash

线性探测(Linear Probe)是一种比较直观简洁的 Hash Table 实现方式了。

其基本思路是如果映射之后的 key 存储的位置已经被占用了,那么它会依次遍历数组,直到找到一个空闲的位置插入数据。

如下,新插入的数据 E 通过计算后,其位置在 A 的位置。

图片

但是 A 处已经有数据了,此时发生了冲突,所以会向后遍历,然后找到 D 之后的空闲位置插入。

图片

删除的逻辑比较类似,也是通过哈希函数计算 key 的位置,然后找到对应的数据并删除。如果 key 并不在原来的位置上,那么需要像插入一样遍历,直到找到目标 key。

删除一般有两种做法,一是直接在删除的位置设置一个墓碑值,表示其已被删除,二是移动其他的元素来填充删除的位置,这种方式并不常用。

重复 key哈希表中对于重复的 key 的处理方式一般有两种,一是通过一个 value 链表的方式,将同一个 key 的多个元素串联起来。

图片

这种方式比较简单直观,另一种方式是重复存储,把每个 key 都当做是独立的,插入方式和上面描述的完全一致。

图片

Robin Hood Hash

robin hood 哈希类似于线性探测,并有一定的改进。

它会记录每个 key 与其原始 hash 映射的位置的距离,例如下图中的 A,因为插入前没有任何数据,不存在哈希冲突,所以 A 记录的距离是 0。

图片

如果此时插入数据 C,如果 C 映射的位置也是 A,这样就产生了哈希冲突,于是向下探测一位,将 C 插到 A 之后的位置,这时候 C 与其原始映射位置的距离就是 1。

图片

当又有新的 key 插入时,如果产生了冲突,那么继续向后探测,并且比较映射距离的值,如果新插入的 key 的距离大于该位置的值,则将新的 key 插入。

图片

例如上面的这个例子,如果新插入的 E 映射到了 A 的位置,此时 E 的距离是 0,和 A 的距离相等,继续向下,此时 E 的距离是 1,和 C 相等,又继续,此时 E 变为 2,大于了 D 的距离 1,于是将 E 插入到 D 的位置,并且将 D 挪到到下一个空闲的位置。

图片

Cuckoo Hash

cuckoo hash 使用多个哈希表,并且每个哈希表使用一个不同 seed (随机种子)的哈希函数。当插入数据时,对 key 轮流用每个哈希函数都计算哈希值,如果对应的哈希表有空闲空间,则直接插入。

例如下面的例子,使用了两个哈希表,插入 key A 的时候,计算两个哈希值,并且查询到第一个哈希表有空闲,则直接将数据插入到哈希表 1 中。

图片

如果此时在插入一条数据 B,如果在哈希表 1 中有冲突,但是在哈希表 2 中没有冲突,则将数据插入到哈希表 2 中。

图片

如果此时再插入一个 key C,经过哈希函数计算后,发现它和两个哈希表都有冲突。

图片

这时候需要选择一个哈希表,将其中的 key 先拿出来,腾一个位置给 C,例如可以将 C 插入到 A 的位置。然后对 A 再计算哈希值,如果 A 在哈希表 2 中没有冲突,则直接将 A 插入到哈希表 2 中。

cuckoo hash 在 Github 上也有对应的一些实现:https://github.com/efficient/libcuckoo

Dynamic Hash Scheme

前面提到的这几种哈希表的实现方式,都可以认为是静态的,即哈希表中能存储多少数据,是一开始就确定下来的,并不会涉及到扩容。

但实际环境中,我们大多数时候都希望哈希表是可以随着数据量的增长而扩张的,下面再介绍几种更常用的,可以自动动态扩容的哈希表实现。

Chained Hash

链式哈希将一个哈希表通过多个 bucket 来维护,如果出现了哈希冲突,则将相同的 key 放到同一个 bucket 中,如果 bucket 超过了规定的容量,则以链表串联起一个新的 bucket。

每个 bucket 一般会有一个指针,标识其位置,当一个 key 经过 hash 之后,可以通过这个指针找到它所属的 bucket。

图片

Extendible Hash

extendible hash(可扩展哈希)和 chained hash 比较类似,都使用到了bucket 这个概念,同时也会有一个执行 bucket 的指针数组。

与之不同的是,extendible hash 将 key 计算哈希值后,会将其值转换为一个二进制表示,然后它会维护一个 global counter,记录定位到 bucket 指针数组,需要取 key 的二进制的多少位;每个 bucket 也有一个 counter,记为 local counter,表示的是定位到该 bucket 需要二进制的多少位。

图片

例如上面的例子,第一个 bucket 的 counter 是 1 ,当 key 定位到该 bucket 的时候,需要取 key 的前一位。而 bucket 2 和 3 的 counter 都是 2,需要取二进制的前两位。

如果需要查询数据,先对 key 计算哈希值,例如下图中的 A,计算其哈希值后,global counter 是 2,所以只需要取前两位即可,然后通过 bucket 的指针获取到 bucket 的位置,遍历其中的数据进行查找。

图片

如果需要新插入数据,则和查找的过程类似,同样计算哈希值,然后找到对应的 bucket,将数据放到 bucket 的空闲位置即可。

如果对应的 bucket 没有空闲的位置了,这时候需要进行 split 分裂操作。

首先将 global counter 的值增加 1,然后新建一个 bucket,将旧的对应的那个 bucket 的 counter 也增加 1,并且让新的 bucket 的 counter 等于这个值。然后重新通过这个 key 的二进制位来移动旧的 bucket 中的数据。

例如下面的例子,需要插入 key C,但是它所映射的 bucket 已经满了。

图片

此时将 global counter 增加为 3,并且新增一个 bucket,counter 为旧的值加一,也为 3。然后将旧的那个 bucket 按照新的进制位重新存放,此时 bucket 中就有空闲的位置了。

图片

更详细内容可以参考:https://zhuanlan.zhihu.com/p/375039823

Linear Hash

前面提到的 extendible hash 在分裂的时候,需要扩展 bucket 指针数组(又叫 slot array),这时候一般需要对哈希表加全局锁,以防止并发读写冲突。但是这样锁的粒度较大,容易造成哈希表的读写瓶颈。

另一种 linear hash 会维护一个分裂指针 split pointer,当有任意的 bucket 分裂时,split pointer 指向的 bucket 也会分裂。这种方式介绍不多,实际使用应该也较少,就不详细介绍了。

Conclusion

哈希表是一个高效的数据结构,大多时候能够在 O(1) 的情况下插入和查询数据,在数据库系统中,有很多地方都使用到了哈希表,例如前面提到的 page table,page directory,以及执行 sql 查询时一些用于 join 的临时数据结构。

但是哈希表的应用场景也有限,因为它存储的所有 key 都是无序的,这样虽然适合点查,但是无法进行范围扫描,在更加通用的场景下,数据库中的表索引使用最广泛的还是 B+ 树。

责任编辑:武晓燕 来源: roseduan写字的地方 数据磁盘管理内存

(责任编辑:休闲)

    推荐文章
    • 邮政银行小微易贷申请流程是怎样的 可以网上提出申请吗?

      邮政银行小微易贷申请流程是怎样的 可以网上提出申请吗?很多中小微企业碰到资金周转不开的时候,会去贷款来维持企业正常运营,其中邮政银行小微易贷就是一款经营性贷款,适合中小微企业融资。考虑到有不少企业主和法人代表对邮政银行小微易贷申请流程不清楚,这里就来简单 ...[详细]
    • 兄弟姐妹多可能影响心理健康

      兄弟姐妹多可能影响心理健康本报讯 近日,一项针对美国和中国青少年的大型分析显示,拥有较多兄弟姐妹的青少年的心理健康状况比兄弟姐妹较少的青少年差。具体细节则取决于兄弟姐妹的年龄、年龄间隔等因素。“其他研究表明,有更多的兄弟姐妹会 ...[详细]
    • 3小时到货!这份“年货”真的是坐了火箭

      3小时到货!这份“年货”真的是坐了火箭◎ 陈长青 薛英民 科技日报记者 何亮 付毅飞1月18日1时46分,天舟七号货运飞船在与长征七号火箭分离约3小时后,成功对接于空间站天和核心舱后向端口,取得了我国2024年载人航天工程交会对接任务的开 ...[详细]
    • 兄弟姐妹多可能影响心理健康

      兄弟姐妹多可能影响心理健康本报讯 近日,一项针对美国和中国青少年的大型分析显示,拥有较多兄弟姐妹的青少年的心理健康状况比兄弟姐妹较少的青少年差。具体细节则取决于兄弟姐妹的年龄、年龄间隔等因素。“其他研究表明,有更多的兄弟姐妹会 ...[详细]
    • ST地矿(000409.SZ):拟向关联方兖矿集团借款不超12亿元 构成关联交易

      ST地矿(000409.SZ):拟向关联方兖矿集团借款不超12亿元 构成关联交易ST地矿(000409.SZ)公布,根据公司及子公司的经营发展的实际需要,本着公平合理、互惠互利的原则,公司拟向关联方兖矿集团有限公司(“兖矿集团”)借款不超过人民币12亿元, ...[详细]
    • “小柯”秀

      “小柯”秀《细胞》改变转录延伸产生遗传血癌倾向美国哈佛医学院的Vijay G. Sankaran等人揭示了通过改变的转录延伸产生的遗传血癌倾向。相关研究成果近日在线发表于《细胞》。研究人员在一个大型人群队列中进 ...[详细]
    • 保交楼时代下,珠实地产诠释交付新标准

      保交楼时代下,珠实地产诠释交付新标准提前一年交付,国企实力红盘再次“超常发挥”在过去一年,监管部门推出了一系列“保交楼、保民生、保稳定”的举措,并取得卓然成效。在“保交楼”数量攀升的另一面,房企也瞄准行业趋势变化,不断打磨产品力和交付力 ...[详细]
    • 在追赶中反超

      在追赶中反超【创新故事】    ◎本报记者 代小佩    随着最后一层纱布掀开,阳光映入张顺化名)的眼帘。    在经历失明的焦灼和痛苦后,这位20岁的小伙子终于重见光明。令人惊喜的变化,源于不久前他的左眼植入了 ...[详细]
    • 360能贷款吗?旗下360借条借款具体情况是怎样的?

      360能贷款吗?旗下360借条借款具体情况是怎样的?360公司创立于2005年,起初是以提供互联网安全服务为目的,比较被大家熟知的有360安全卫士、360手机卫士、360安全浏览器等产品,后来随着信用贷款的普及,也推出了金融贷款类的产品,即360借条, ...[详细]
    • 成功研制小动物头戴式光纤光声显微镜

      成功研制小动物头戴式光纤光声显微镜头戴式显微镜以光学激发超声探测方式获得大脑皮层血管分布及血氧饱和度信息示意图。本报讯记者朱汉斌)暨南大学教授关柏鸥团队研制出一种头戴式显微镜,能够对自由运动状态的小动物进行脑功能成像,以单血管分辨率观 ...[详细]
    热点阅读