快捷搜索:  汽车  科技

redishash类型简介(Redis数据类型之Hash型)

redishash类型简介(Redis数据类型之Hash型)例如, 我们执行以下 HSET 命令, 那么服务器将创建一个列表对象作为 profile 键的值:先添加到哈希对象中的键值对会被放在压缩列表的表头方向,而后来添加到哈希对象中的键值对会被放在压缩列表的表尾方向。2、hashtable 编码的哈希对象使用字典作为底层实现ziplist 编码的哈希对象使用压缩列表作为底层实现, 每当有新的键值对要加入到哈希对象时, 程序会先将保存了键的压缩列表节点推入到压缩列表表尾, 然后再将保存了值的压缩列表节点推入到压缩列表表尾, 因此:保存了同一键值对的两个节点总是紧挨在一起, 保存键的节点在前, 保存值的节点在后;

一、前言

Redis提供了5种数据类型:String(字符串)、Hash(哈希)、List(列表)、Set(集合)、Zset(有序集合),理解每种数据类型的特点对于redis的开发和运维非常重要。

redishash类型简介(Redis数据类型之Hash型)(1)

Redis中的 hash 是我们经常使用到的一种数据类型,根据使用方式的不同,可以应用到很多场景中。

二、实现分析

由上述结构图可知,Hash类型有以下两种实现方式:

1、ziplist 编码的哈希对象使用压缩列表作为底层实现

2、hashtable 编码的哈希对象使用字典作为底层实现

1.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 编码, 其中对象所使用的压缩列表结构如下图所示。

redishash类型简介(Redis数据类型之Hash型)(2)

redishash类型简介(Redis数据类型之Hash型)(3)

2.hashtable 编码作为底层实现

hashtable 编码的哈希对象使用字典作为底层实现, 哈希对象中的每个键值对都使用一个字典键值对来保存:

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

例如, 如果前面 profile 键创建的不是 ziplist 编码的哈希对象, 而是 hashtable 编码的哈希对象, 那么这个哈希对象结构如下图所示。

redishash类型简介(Redis数据类型之Hash型)(4)

三、命令实现

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

redishash类型简介(Redis数据类型之Hash型)(5)

四、编码转换

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

哈希对象保存的所有键值对的键和值的字符串长度都小于 64 字节; 哈希对象保存的键值对数量小于 512 个;

不能满足这两个条件的哈希对象需要使用 hashtable 编码。

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

对于使用 ziplist 编码的列表对象来说, 当使用 ziplist 编码所需的两个条件的任意一个不能被满足时, 对象的编码转换操作就会被执行: 原本保存在压缩列表里的所有键值对都会被转移并保存到字典里面, 对象的编码也会从 ziplist 变为 hashtable 。

以下代码展示了哈希对象编码转换的情况:

1.键的长度太大引起编码转换

# 哈希对象只包含一个键和值都不超过 64 个字节的键值对 redis> HSET book name "Mastering C in 21 days" (integer) 1 redis> OBJECT ENCODING book "ziplist" # 向哈希对象添加一个新的键值对,键的长度为 66 字节 redis> HSET book long_long_long_long_long_long_long_long_long_long_long_description "content" (integer) 1 # 编码已改变 redis> OBJECT ENCODING book "hashtable"2.值的长度太大引起编码转换

# 哈希对象只包含一个键和值都不超过 64 个字节的键值对 redis> HSET blah greeting "hello world" (integer) 1 redis> OBJECT ENCODING blah "ziplist" # 向哈希对象添加一个新的键值对,值的长度为 68 字节 redis> HSET blah story "many string ... many string ... many string ... many string ... many" (integer) 1 # 编码已改变 redis> OBJECT ENCODING blah "hashtable"3.键值对数量过多引起编码转换

# 创建一个包含 512 个键值对的哈希对象 redis> EVAL "for i=1 512 do redis.call('HSET' KEYS[1] i i) end" 1 "numbers" (nil) redis> HLEN numbers (integer) 512 redis> OBJECT ENCODING numbers "ziplist" # 再向哈希对象添加一个新的键值对,使得键值对的数量变成 513 个 redis> HMSET numbers "key" "value" OK redis> HLEN numbers (integer) 513 # 编码改变 redis> OBJECT ENCODING numbers "hashtable"五、要点总结

1.Hash类型两种编码方式,ziplist 与 hashtable

2.hashtable 编码的哈希对象使用字典作为底层实现

3.ziplist 与 hashtable 编码方式之间存在转换

猜您喜欢: