数据库中使用到哈希表的结构:
internal meta-data:内部元数据
core data storage:核心数据集结构存储
temporary data structures:临时数据
table indexes:表的索引
HASH TABLES
design decisions
考虑两个方面:哈希表的数据结构,并发问题;
哈希表本质是一个表,一列是key,一列是value,类似于map,但是map的key不重复,哈希表的key可能会重复
哈希表的特点:
空间复杂度:O(n),占的空间和其存储的数据是线性相关的
时间复杂度:平均:O(1);最差:O(n),最差的时候是key的值全部重复,只能存在一个桶里
static hash table
静态哈希表。
对于静态哈希表:我们假设每个键都是独一无二的,不同的key对应的桶不冲突。(这是不可能的)
设计哈希表
hash 函数
如何将大范围的key映射到哈希表小范围的桶里;速度和碰撞率?
哈希schema
如何处理碰撞;是直接分配一个大的哈希表还是通过额外的措施(动态调整大小)来解决key的冲突?
哈希函数
any input key => return an integer
整数可以代表这个key
哈希表使用的不是一个加密(数据加密完之后,无法获得数据原先的任何一种情况)的哈希函数,该加密过程比较复杂(相对于mod函数之类)
哈希函数的要求就是:快,同时碰撞少;
常用哈希函数
CRC-64、MurmurHash、Google CityHash、Facebook XXhash、Google FarmHash
哈希函数的性能对比:
随着key的长度的改变,吞吐量的改变
静态哈希schemes
线性探测哈希(开放寻址哈希)
插入时:如果出现碰撞,则开始向下一个地址寻找,存放到下一个空的位置
删除时:对碰撞的处理,
C与A碰撞,删除C后,此时查D会出问题:
解决方法:
Tombstone(墓碑),设定此处为原本有数据,但已删除。
Movement:整理后续的冲突数据,里面有很多问题需要处理
非唯一键(NON-Unique Keys)
即一个key对应多个value。
可以使用链表存储,key指向一个链表,该链表存储了所有的value
或者,使用key|value作为key
Robin hood hashing
基础数据结构:开放寻址哈希。但,除了键值外,还需要记录[0],表示数据被推了多少格的位置。
如果此时hash(E) = hash(A),如果把E插入,此时会占D的位置;
cuckoo hashing
(杜鹃鸟)
多个哈希表。碰撞时,找其他的哈希表的存储,如果备用哈希表仍然冲突,先去最初的hash table,再去其他备用hash表来。
observation
之前方法的缺点:空间始终是有限的,对于静态的哈希表而言。无法动态伸缩
三种动态的哈希表:chained hashing、extendible hashing、linear Hashing
chained hashing
拉链式哈希表
引入桶的概念
extendible hashing
只看key的二进制位的前两位,
桶满怎么处理:把看key的位数增大,去看hash值的前三位,将桶的个数也增加,但是需要将现有桶内存的数据要再重新整理一下
Linear hashing
桶满怎么处理:overflow桶
当前槽溢出,从0号槽开始分加槽,此时分加的槽,使用第二个哈希函数。再发现有槽有溢出时,再将1号槽分加。直到所有槽都会进行分加,接下来如果还增加,那再从0号槽开始分加。
例如:当检测到,指向0号槽的数据,再计算一次第二个哈希函数的结果,再来说最终放到哪个槽里。
总结
哈希表对于查询而言,支持O(1)的查找时间复杂度。哈希表在DBMS中有很多地方的应用。
哈希表在速度和灵活性(空间伸缩)之间平衡
哈希表通常不用于表的索引(哈希表对于范围查询无用)