Bootstrap

【redis】哈希类型详解

一、哈希类型的介绍

⼏乎所有的主流编程语⾔都提供了哈希(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 …]删除 fieldO(k), k 是 field 个数
hlen key计算 field 个数O(1)
hgetall key获取所有的 field-valueO(k), k 是 field 个数
hmget field [field …]批量获取 field-valueO(k), k 是 field 个数
hmset field value [field value …]批量获取 field-valueO(k), k 是 field 个数
hexists key field判断 field 是否存在O(1)
hkeys key获取所有的 fieldO(k), k 是 field 个数
hvals key获取所有的 valueO(k), k 是 field 个数
hsetnx key field value设置值,但必须在 field 不存在时才能设置成功O(1)
hincrby key field n对应 field-value +nO(1)
hincrbyfloat key field n对应 field-value +nO(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 类型是一种键值对集合,适合用于存储对象,因此在很多场景下都有着广泛的应用。以下是一些常见的应用场景:

  1. 存储对象:Hash 类型可以存储多个键值对,非常适合用于存储对象。例如,你可以使用 Hash 类型存储用户的信息,如用户名、密码、邮箱等;
  2. 数据分析:你可以使用 Hash 类型存储各种统计数据,例如用户的行为数据,然后进行数据分析;
  3. 社交网络:在社交网络应用中,你可以使用 Hash 类型存储用户的朋友列表、粉丝列表等
;