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 不同时,有两种做法:

  1. Separate Linked List

  2. 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