哈希类型详解
一、哈希类型的介绍
⼏乎所有的主流编程语⾔都提供了哈希(hash)类型,它们的叫法可能是哈希、字典、关联数组、映射。在 Redis 中,哈希类型是指值本⾝⼜是⼀个键值对结构,形如 key = “key”,value = { { field1, value1 }, …, {fieldN, valueN } },Redis 键值对和哈希类型⼆者的关系可以⽤下图表示
字符串和哈希类型对⽐ :
哈希类型中的映射关系通常称为 field-value,⽤于区分 Redis 整体的键值对(key-value),注意这⾥的 value 是指 field 对应的值,不是键(key)对应的值,请注意 value 在不同上下⽂的作⽤
二、哈希类型的常用命令
2.1 HSET
设置 hash 中指定的字段(field)的值(value)
语法:
HSET key field value [field value ...]
返回值:添加的字段的个数
使用示例:
127.0.0.1:6379> hset key field 'hello'
(integer) 1
127.0.0.1:6379> hget key field
"hello"
2.2 HGET
获取 hash 中指定字段的值
语法:
HGET key field
返回值:字段对应的值或者 nil
使用示例:
127.0.0.1:6379> hset key field 'foo'
(integer) 1
127.0.0.1:6379> hget key field
"foo"
127.0.0.1:6379> hget key field1
(nil)
2.3 HEXISTS
判断 hash 中是否有指定的字段
语法:
HEXISTS key field
返回值:1 表⽰存在,0 表⽰不存在
使用示例:
127.0.0.1:6379> hset key field 'foo'
(integer) 1
127.0.0.1:6379> hexists key field
(integer) 1
127.0.0.1:6379> hexists key field1
(integer) 0
2.4 HDEL
删除 hash 中指定的字段
语法:
HDEL key field [field ...]
返回值:本次操作删除的字段个数
使用示例:
127.0.0.1:6379> hset key field 'foo'
(integer) 1
127.0.0.1:6379> hdel key field
(integer) 1
127.0.0.1:6379> hdel key field1
(integer) 0
2.5 HKEYS
获取 hash 中的所有字段
语法:
HKEYS key
返回值:字段列表
使用示例:
27.0.0.1:6379> hset key field 'hello'
(integer) 1
127.0.0.1:6379> hset key field2 'world'
(integer) 1
127.0.0.1:6379> hkeys key
1) "field"
2) "field2"
2.6 HAVLS
获取 hash 中的所有的值
语法:
HVALS key
返回值:所有的值
使用示例:
127.0.0.1:6379> hset key field 'hello'
(integer) 1
127.0.0.1:6379> hset key field2 'world'
(integer) 1
127.0.0.1:6379> hvals key
1) "hello"
2) "world"
2.7 HGETALL
获取 hash 中的所有字段以及对应的值
语法:
HGETALL key
返回值:字段和对应的值
使用示例:
127.0.0.1:6379> hset key field 'hello'
(integer) 1
127.0.0.1:6379> hset key field2 'world'
(integer) 1
127.0.0.1:6379> hgetall key
1) "field"
2) "hello"
3) "field2"
4) "world"
在使⽤ HGETALL 时,如果哈希元素个数⽐较多,会存在阻塞 Redis 的可能。如果开发⼈员只需要获取部分 field,可以使⽤ HMGET,如果⼀定要获取全部 field,可以尝试使⽤ HSCAN 命令,该命令采⽤渐进式遍历哈希类型,HSCAN 会在后续介绍
2.8 HMGET
⼀次获取 hash 中多个字段的值
语法:
HMGET key field [field ...]
返回值:字段对应的值或者 nil
使用示例:
127.0.0.1:6379> hset key field 'hello'
(integer) 1
127.0.0.1:6379> hset key field2 'world'
(integer) 1
127.0.0.1:6379> hmget key field field2 nofield
1) "hello"
2) "world"
3) (nil)
2.9 HLEN
获取 hash 中的所有字段的个数
语法:
HLEN key
返回值:字段个数
使用示例:
127.0.0.1:6379> hset key field 'hello'
(integer) 1
127.0.0.1:6379> hset key field2 'world'
(integer) 1
127.0.0.1:6379> hlen key
(integer) 2
2.10 HSETNX
在字段不存在的情况下,设置 hash 中的字段和值
语法:
HSETNX key field value
返回值:1 表⽰设置成功,0 表⽰失败
使用示例:
127.0.0.1:6379> hsetnx key field 'hello'
(integer) 1
127.0.0.1:6379> hsetnx key field 'world'
(integer) 0
127.0.0.1:6379> hget key field
"hello"
2.11 HINCRBY
将 hash 中字段对应的数值添加指定的值
语法:
HINCRBY key field increment
返回值:该字段变化之后的值
使用示例:
127.0.0.1:6379> hset key field 5
(integer) 1
127.0.0.1:6379> hincrby key field 1
(integer) 6
127.0.0.1:6379> hincrby key field -1
(integer) 5
127.0.0.1:6379> hincrby key field -10
(integer) -5
2.12 HINCRBYFLOAT
HINCRBY 的浮点数版本
语法:
HINCRBYFLOAT key field increment
返回值:该字段变化之后的值
使用示例:
127.0.0.1:6379> hset key field 10.00
(integer) 1
127.0.0.1:6379> hincrbyfloat key field 0.1
"10.1"
127.0.0.1:6379> hincrbyfloat key field -5
"5.1"
127.0.0.1:6379> hset key field 5.0e3
(integer) 0
127.0.0.1:6379> hincrbyfloat key field 2.0e2
"5200"
三、哈希类型命令小结
命令 | 执⾏效果 | 时间复杂度 |
---|---|---|
hset key field value | 设置值 | O(1) |
hget key field | 获取值 | O(1) |
hdel key field [field …] | 删除 field | O(k), k 是 field 个数 |
hlen key | 计算 field 个数 | O(1) |
hgetall key | 获取所有的 field-value | O(k), k 是 field 个数 |
hmget field [field …] | 批量获取 field-value | O(k), k 是 field 个数 |
hmset field value [field value …] | 批量获取 field-value | O(k), k 是 field 个数 |
hexists key field | 判断 field 是否存在 | O(1) |
hkeys key | 获取所有的 field | O(k), k 是 field 个数 |
hvals key | 获取所有的 value | O(k), k 是 field 个数 |
hsetnx key field value | 设置值,但必须在 field 不存在时才能设置成功 | O(1) |
hincrby key field n | 对应 field-value +n | O(1) |
hincrbyfloat key field n | 对应 field-value +n | O(1) |
hstrlen key field | 计算 value 的字符串⻓度 | O(1) |
四、哈希类型内部编码
哈希的内部编码有两种:
- ziplist(压缩列表):当哈希类型元素个数⼩于 hash-max-ziplist-entries 配置(默认 512 个),同时所有值都⼩于 hash-max-ziplist-value 配置(默认 64 字节)时,Redis 会使⽤ ziplist 作为哈希的内部实现,ziplist 使⽤更加紧凑的结构实现多个元素的连续存储,所以在节省内存⽅⾯⽐ hashtable 更加优秀
- hashtable(哈希表):当哈希类型⽆法满⾜ ziplist 的条件时,Redis 会使⽤ hashtable 作为哈希的内部实现,因为此时 ziplist 的读写效率会下降,⽽ hashtable 的读写时间复杂度为 O(1)
hash-max-ziplist-entries
:这个参数用于设置压缩列表可以存储的最大节点数量。如果一个 Hash 类型的元素数量超过这个值,那么就会从压缩列表切换到散列表。默认值为 512
hash-max-ziplist-value
:这个参数用于设置压缩列表中每个节点的最大值大小(以字节为单位)。如果一个 Hash 类型的任何元素的大小超过这个值,那么就会从压缩列表切换到哈希表。默认值为 64
从压缩列表转换到哈希表的条件:当 Hash 类型存储的字段和值的数量超过 hash-max-ziplist-entries
的值,或者任何字段或值的大小超过 hash-max-ziplist-value
的值时,Redis 会将底层结构从压缩列表转换为哈希表。这个过程是自动进行的,对用户来说是透明的,压缩列表转换为哈希表是单向的,不可逆
下面演示这两种类型:
①当 field 个数⽐较少且没有⼤的 value 时,内部编码为 ziplist:
127.0.0.1:6379> hmset hashkey f1 v1 f2 v2
OK
//查看哈希内部编码类型
127.0.0.1:6379> object encoding hashkey
"ziplist"
②当有 value ⼤于 64 字节时,内部编码会转换为 hashtable:
127.0.0.1:6379> hset hashkey f3 "one string is bigger than 64 bytes ... "
OK
127.0.0.1:6379> object encoding hashkey
"hashtable"
③当 field 个数超过 512 时,内部编码也会转换为 hashtable:
127.0.0.1:6379> hmset hashkey f1 v1 h2 v2 f3 v3 ... 省略 ... f513 v513
OK
127.0.0.1:6379> object encoding hashkey
"hashtable"
五、哈希类型应用场景
Redis 的 Hash 类型是一种键值对集合,适合用于存储对象,因此在很多场景下都有着广泛的应用。以下是一些常见的应用场景:
- 存储对象:Hash 类型可以存储多个键值对,非常适合用于存储对象。例如,你可以使用 Hash 类型存储用户的信息,如用户名、密码、邮箱等;
- 数据分析:你可以使用 Hash 类型存储各种统计数据,例如用户的行为数据,然后进行数据分析;
- 社交网络:在社交网络应用中,你可以使用 Hash 类型存储用户的朋友列表、粉丝列表等