哈希对象

    ziplist 编码的哈希对象使用压缩列表作为底层实现,每当有新的键值对要加入到哈希对象时,程序会先将保存了键的压缩列表节点推入到压缩列表表尾,然后再将保存了值的压缩列表节点推入到压缩列表表尾,因此:

    • 先添加到哈希对象中的键值对会被放在压缩列表的表头方向,而后来添加到哈希对象中的键值对会被放在压缩列表的表尾方向。

    举个例子,如果我们执行以下 HSET 命令,那么服务器将创建一个列表对象作为 profile 键的值:

    如果 profile 键的值对象使用的是 ziplist 编码,那么这个值对象将会是图 8-9 所示的样子,其中对象所使用的压缩列表如图 8-10 所示。

    digraph { label = "\n 图 8-10 profile 哈希对象的压缩列表底层实现"; // node [shape = record]; ziplist [label = " zlbytes | zltail | zllen | <key1> \"name\" | <value1> \"Tom\" | <key2> \"age\" | <value2> 25 | <key3> \"career\" | <value3> \"Programmer\" | zlend "]; node [shape = plaintext]; edge [style = dashed]; kv1 [label = "第一个添加的键值对"]; kv1 -> ziplist:key1 [label = "键"]; kv1 -> ziplist:value1 [label = "值"]; kv2 [label = "第二个添加的键值对"]; kv2 -> ziplist:key2; kv2 -> ziplist:value2; kvN [label = "最新添加的键值对"]; kvN -> ziplist:key3; kvN -> ziplist:value3;}

    • 字典的每个键都是一个字符串对象,对象中保存了键值对的键;

    举个例子,如果前面 profile 键创建的不是 ziplist 编码的哈希对象,而是 hashtable 编码的哈希对象,那么这个哈希对象应该会是图 8-11 所示的样子。

    当哈希对象可以同时满足以下两个条件时,哈希对象使用 ziplist 编码:

    • 哈希对象保存的所有键值对的键和值的字符串长度都小于 64 字节;
    • 哈希对象保存的键值对数量小于 512 个;不能满足这两个条件的哈希对象需要使用 编码。

    注意

    这两个条件的上限值是可以修改的,具体请看配置文件中关于 hash-max-ziplist-value 选项和 hash-max-ziplist-entries 选项的说明。

    以下代码展示了哈希对象因为键值对的键长度太大而引起编码转换的情况:

    除了键的长度太大会引起编码转换之外,值的长度太大也会引起编码转换,以下代码展示了这种情况的一个示例:

    最后,以下代码展示了哈希对象因为包含的键值对数量过多而引起编码转换的情况:

    哈希命令的实现

    因为哈希键的值为哈希对象,所以用于哈希键的所有命令都是针对哈希对象来构建的,表 8-9 列出了其中一部分哈希键命令,以及这些命令在不同编码的哈希对象下的实现方法。


    表 8-9 哈希命令的实现