「Redis数据结构」哈希对象(Hash)
文章目录
- 「Redis数据结构」哈希对象(Hash)
- 一、概述
- 二、编码
- ZipList
- HashTable
- 三、编码转换
一、概述
Redis中hash对象是一个string类型的field和value的映射表,hash特别适合用于存储对象。作为哈希对象的编码,有二种一是ziplist编码, 二是hashtable编码。在不同情况下编码是可以转换的。在Redis 中每个 hash 可以存储 232 - 1 键值对(40多亿)。
Hash结构与Redis中的Zset非常类似:
- 都是键值存储
- 都需求根据键获取值
- 键必须唯一
区别
- zset的键是member,值是score;hash的键和值都是任意值
- zset要根据score排序;hash则无需排序
因此,Hash底层采用的编码与Zset也基本一致,只需要把排序有关的SkipList去掉。
二、编码
哈希对象的编码可以是
ziplist
或者hashtable
。
ZipList
ziplist
编码的哈希对象使用压缩列表作为底层实现, 每当有新的键值对要加入到哈希对象时, 程序会先将保存了键的压缩列表节点推入到压缩列表表尾, 然后再将保存了值的压缩列表节点推入到压缩列表表尾, 因此:
- 保存了同一键值对的两个节点总是紧挨在一起, 保存键的节点在前, 保存值的节点在后;
- 先添加到哈希对象中的键值对会被放在压缩列表的表头方向, 而后来添加到哈希对象中的键值对会被放在压缩列表的表尾方向。
如果我们执行以下 HSET 命令, 那么服务器将创建一个列表对象作为 profile
键的值:
redis> HSET profile name "Tom"
(integer) 1
redis> HSET profile age 25
(integer) 1
redis> HSET profile career "Programmer"
(integer) 1
如果 profile
键的值对象使用的是 ziplist
编码, 那么这个值对象将会是如图所示。
HashTable
hashtable
编码的哈希对象使用字典作为底层实现, 哈希对象中的每个键值对都使用一个字典键值对来保存:
- 字典的每个键都是一个字符串对象, 对象中保存了键值对的键;
- 字典的每个值都是一个字符串对象, 对象中保存了键值对的值。
举个例子, 如果前面 profile
键创建的不是 ziplist
编码的哈希对象, 而是 hashtable
编码的哈希对象。
三、编码转换
Hash结构默认采用ZipList编码,用以节省内存。 ZipList中相邻的两个entry 分别保存field和value
当数据量较大时,Hash结构会转为HT编码,也就是Dict,触发条件有两个:
(1)哈希对象保存的所有键值对的键和值的字符串长度都小于64字节;
(2) 哈希对象保存的键值对数量小于512个。
当不能满足这两个条件的哈希对象需要使用hashtable编码。
对于上面编码转换的两个条件,上限值是可以修改的,具体看配置文件中关于hash-max-ziplist-value选项和hash-max-ziplist-entries选项说明。
127.0.0.1:6379> config get hash-max-ziplist-value
1) "hash-max-ziplist-value"
2) "64"
127.0.0.1:6379> config get hash-max-ziplist-entries
1) "hash-max-ziplist-entries"
2) "512"
参考
《Redis 设计与实现》
黑马程序员