散列

  • 散列的基本操作

  • 散列的优点

  • 常见应用场景

一个散列由多个域值对(field-value pair)组成,散列的域和值都可以是文字、整数、浮点数或者二进制数据。

同一个散列里面的每个域必须是独一无二、各不相同的,而域的值则没有这一要求,换句话说,不同域的值可以是重复的。

通过命令,用户可以对散列执行设置域值对、获取域的值、检查域是否存在等操作,也可以让 Redis 返回散列包含的所有域、所有值或者所有域值对。

散列的基本操作

关联域值对、获取域的值、检查域是否存在、获取域值对的数量,等等。

HSET key field value

关联域值对

在散列键 key 中关联给定的域值对 field 和 value 。如果域 field 之前没有关联值,那么命令返回 1;如果域 field

已经有关联值,那么命令用新值覆盖旧值,并返回 0。复杂度为 O(1) 。

HGET key field

获取域关联的值

返回散列键 key 中,域 field 所关联的值。如果域 field 没有关联值,那么返回 nil。复杂度为 O(1)。

HSETNX key field value

仅当域不存在时,关联域值对

如果散列键 key 中,域 field 不存在(也即是,还没有与之相关联的值),那么关联给定的域值对 field 和value 。

如果域 field 已经有与之相关联的值,那么命令不做动作。复杂度为 O(1) 。

HEXISTS key field

检查域是否存在

查看散列键 key 中,给定域 field 是否存在:存在返回 1 ,不存在返回 0 。复杂度为 O(1) 。

HDEL key field [field …]

删除给定的域值对

删除散列键 key 中的一个或多个指定域,以及那些域的 值。不存在的域将被忽略。命令返回被成功 删除的域值对数量。复杂度为 O(N) ,N

为被删除的域值对数量。

HLEN key

获取散列包含的键值对数量

返回散列键 key 包含的域值对数量。复杂度为 O(1) 。

HMSET key field value [field value …]

在散列键 key 中关联多个域值对,一次设置或获取散列中的多个域值对,相当于同时执行多个 HSET。

复杂度为 O(N) ,N 为输入的域值对数量。

HMGET key field [field …]

返回散列键 key 中,一个或多个域的值,相当于同时执行多个 HGET 。

复杂度为 O(N) , N 为输入的域数量。

获取散列包含的所有域、值、或者域值对

| 命令 | 作用 | 复杂度 |

|-------------|----------------------------------------|-----|

| HKEYS key | 返回散列键 key 包含的所有域。 O(N),N 为被返回域的数量。 |

| HVALS key | 返回散列键 key 中,所有域的值。 O(N),N 为被返回值的数量。 |

| HGETALL key | 返回散列键 key 包含的所有域值对。 O(N),N 为被返回域值对的数量。 |

和字符串键的值一样,在散列里面,域的值也可以被解释为数字,并执行相应的数字操作。

对域的值执行自增操作

虽然 Redis 没有提供与以上两个命令相匹配的 HDECRBY 命令和 HDECRBYFLOAT 命令,但我们同样可以通过将 increment 设为负数来达到做减法的效果。

| 命令 | 作用 | 复杂度 |

|----------------------------------|--------------------------------------|------|

| HINCRBY key field increment | 为散列键key中,域field的值加上整数增量 increment 。 | O(1) |

| HINCRBYFLOAT key field increment | 为散列键key中,域field的值加上浮点数增量 increment 。 | O(1) |

散列键和字符串键效果类似的命令

| 散列命令 | 字符串/数据库命令 |

|--------------|------------------|

| HSET | SET |

| HGET | GET |

| HSETNX | SETNX |

| HDEL | DEL(不仅限于字符串键) |

| HMSET | MSET |

| HMGET | MGET |

| HINCRBY | INCRBY |

| HINCRBYFLOAT | INCRBYFLOAT |

| HEXISTS | EXISTS(不仅限于字符串键) |

散列的优点

  • 将数据放到同一个地方

散列可以让我们将一些相关的信息储存在同一个地方,而不是直接分散地 储存在整个数据库里面,这不仅方便了数据管理,还可以尽量避免误操作发生。

  • 避免键名冲突

在介绍字符串键的时候,我们说过,可以在命名键的时候,使用分割符来避免命名冲突,但更好的办法是直接使用散列键来储存键值对数据。

**

使用字符串键的数据库创建的键数量多,而使用散列键的数据库创建的键数量则少。随着域数量的增加,使用散列会比使用字符串少创建很多数据库键。**

  • 减少内存占用

    • 在一般情况下,保存相同数量的键值对信息,使用散列键比使用字符串键更节约内存。

    • 因为在数据库里面创建的每个键都带有数据库附加的管理信息(比如这个键的类型、最后一次被访问的时间等等),所以数据库里面的键越多,服务器在储存附加管理信息方面耗费的内存就越多,花在管理数据库键上的

      CPU 也会越多。

    • 除此之外,当散列包含的域值对数量比较少的时候,Redis 会自动使用一种占用内存非常少的数据结构来做散列的底层实现,在散列的数量比较多的时候,这一措施对减少内存有很大的帮助。

只要有可能的话,就尽量使用散列键而不是字符串键来储存键值对数据,因为散列键管理方便、能够避免键名冲突、并且还能够节约内存。

一些没办法使用散列键来代替字符串键的情况:

  • 使用二进制位操作命令:因为 Redis 目前支持对字符串键进行 SETBIT、GETBIT、BITOP 等操作,如果你想使用这些操作,那么只能使用字符串键。

  • 使用过期功能:Redis 的键过期功能目前只能对键进行过期操作,而不能对散列的域进行过期操作,因此如果你要对键值对数据使用过期功能的话,那么只能把键值对储存在字符串里面。

常见应用场景

数据行缓存

有时页面上的某个板块,数据往往来源于数据库查询结果,有时甚至是若干次数据库查询,再经过计算统计后的数据结果

如果请求的比较频繁,将会给数据库带来巨大的压力,为了减轻负载,可以对数据结果进行缓存,并不定期地对这些缓存进行更新

这些从数据库取出来的行数据结构正好对应Redis的散列,常见以 前缀:id 为key,存储数据行到散列