哈希是一种将任意长度的输入通过特定算法转换为固定长度输出的技术,这种输出被称为哈希值。这种转换过程可以看作是一种压缩映射,即输入空间通常比输出空间大得多。因此,不同的输入可能会产生相同的输出,这意味着我们不能通过哈希值来唯一确定输入。
哈希表是一种数据结构,用于将数据映射到数组中的某个位置,以便通过数组下标快速访问数据,从而提高数据查询的速度。理论上,这种查询的平均时间复杂度为O(1)。
例如,有四个整数6、7、9、12,需要将它们映射到数组中:
使用哈希表的优点是能最大限度地提高空间利用率,并且查询效率也很高。然而,如果这四个数变为6、7、8、11,由于7和11对4取模的结果都是3,所以它们会占据同一个槽位,这种情况称为冲突。解决冲突的方法包括开放地址法、再散列法和链地址法。Redis采用的是链地址法,即将冲突的数据通过链表连接起来。
在Redis中,哈希表被称为字典,Redis字典使用哈希表作为底层实现,每个哈希表节点保存一个键值对。实际上,Redis数据库底层也是使用哈希表来存储键值对的。Redis中的哈希表采用了链地址法处理冲突,当多个键名映射到相同位置时,系统会将这些键值对以链表的形式存储在一起。为了控制哈希表占用的内存大小,Redis使用了双哈希表结构,并逐渐扩展哈希表容量。每个键值对在保存前会经过类似HASH(key) MOD N
的方法计算出一个值,以确定其在哈希表中的位置。
Redis中的哈希表非常适合存储对象,因为将对象的每个字段存储为单个字符串类型,再将其存储在哈希表中,这样会占用更少的内存并且便于存储整个对象。Redis中的哈希表是一个字符串类型的字段和值的映射表,增删操作的平均时间复杂度为O(1)。这是因为哈希表的内部结构包括zipmap和hash两种形式。其中,zipmap可以在存储少量字段的情况下节省内存,但当字段数量较多时,性能会下降。
在Redis中,集合(Set)以普通键值对的方式存储,可以设置过期时间,时间复杂度为O(1)。而哈希表(Hash)以哈希散列表的方式存储,超时时间只能设置在键上,单个字段不能设置过期时间。时间复杂度为O(n),其中n是哈希表中的字段数量。因此,哈希表不适合存储大量字段,而集合更适合存储大量非结构化的数据。
在Redis中,可以使用hset
命令为哈希表中的字段赋值。如果哈希表不存在,则会先创建哈希表再赋值;如果字段已存在,则会覆盖原有值。如果字段是新创建的并且赋值成功,则返回1;如果字段已存在并且值被覆盖成功,则返回0。
选择13亿个Key,每个Key包含4个字段,还是1亿个Key,每个Key包含13亿个字段?答案取决于具体需求。如果追求高效的内存使用和快速查询,使用较少的Key和较多的字段可能更好;如果需要频繁更新数据,选择较多的Key可能更合适。