Hash Tables
本节开始之前,先看一下目前课程的进度状态:
为了支持 DBMS 更高效地从 pages 中读取数据,DBMS 的设计者需要灵活运用一些数据结构及算法,其中对于 DBMS 最重要的两个是:
Hash Tables
Trees
它们可能被用在 DBMS 的多个地方,包括:
Internal Meta-data
Core Data Storage
Temporary Data Structures
Table Indexes
在做相关的设计决定时,通常需要考虑两个因素:
Data Organization:如何将这些数据结构合理地放入 memory/pages 中,以及为了支持更高效的访问,应当存储哪些信息
Concurrency:如何支持数据的并发访问
Hash Tables
Hash Table 是 associative array/dictionary ADT 的实现,它将键映射成对应的值。简介这里不再赘述,可参考 MIT 6.006 Dictionary Problem & Implementation。
Hash Table 主要分为两部分:
Hash Function:
How to map a large key space into a smaller domain
Trade-off between being fast vs. collision rate
Hashing Scheme:
How to handle key collisions after hashing
Trade-off between allocating a large hash table vs. additional instructions to find/insert keys
Hash Functions
由于 DBMS 内使用的 Hash Function 并不会暴露在外,因此没必要使用加密(cryptographic)哈希函数,我们希望它速度越快,collision rate 越低越好。目前各 DBMS 主要在用的 Hash Functions 包括:
Hashing Scheme
Linear Probe Hashing
Linear Probe Hashing 的主要原理在 MIT 6.006 中已经介绍,这里不赘述。
当 keys 可能出现重复,但 value 不同时,有两种做法:
Separate Linked List
Redundant Keys
如下图所示:
通常为了减少 collision 和 comparisons,Hash Table 的大小应当是 table 中元素量的两倍以上。
Robin Hood Hashing
Robin Hood Hashing 是 Linear Probe Hashing 的变种,为了防止 Linear Probe Hashing 出现连续区域导致频繁的 probe 操作。基本思路是 “劫富济贫”,即每次比较的时候,同时需要比较每个 key 距离其原本位置的距离(越近越富余,越远越贫穷),如果遇到一个已经被占用的 slot,如果它比自己富余,则可以直接替代它的位置,然后把它顺延到新的位置。
Cuckoo Hashing
(略)
小结
以上介绍的 Hash Tables 要求使用者能够预判所存数据的总量,否则每次数量超过范围时都需要重建 Hash Table。它可能被应用在 Hash Join 的场景下,如下图所示:
由于 A, B 表的大小都知道,我们就可以预判到 Hash Table 的大小。
Dynamic Hash Tables
与 Static Hash Tables 需要预判最终数据量大小的情况不同,Dynamic Hash Tables 可以按需扩容缩容,本节主要介绍 Chained Hashing,Extendible Hashing 和 Linear Hashing。
Chained Hashing
Chained Hashing 是 Dynamic Hash Tables 的 HelloWorld 实现,每个 key 对应一个链表,每个节点是一个 bucket,装满了就再往后挂一个 bucket。需要写操作时,需要请求 latch。
Extendible Hashing
Extendible Hashing 的基本思路是一边扩容,一边 rehash,如下图所示:
Linear Hashing
基本思想:维护一个指针,指向下一个将被拆分的 bucket,每当任意一个 bucket 溢出(标准自定,如利用率到达阈值等)时,将指针指向的 bucket 拆分。
总结
参考
slides, video
Last updated