本文简单介绍了 Redis 支持的诸多数据类型。

前言

Redis 支持许多数据类型,尽管我们使用最多的仍然是 String。诚然,在大多数场景下,String 似乎都能够解决我们的问题,最多在程序中多几次转换而已。但是,Redis 提供的强大类型可以让我们省去许多复杂的逻辑,更重要的是,它总是会比我们自己实现有着更高的效率,不是吗?

String

String 是最基础的 Redis 数据类型。Redis 的 String 是二进制安全的,这意味着它可以储存任何种类的数据,例如 JPEG 图片或序列化的 Ruby 对象。

String 值支持的最大长度是 512 MB。

你可以使用 Redis 的 String 实现很多有意思的功能,比如你可以:

  • 使用 String 实现一个原子计数器,结合 INCR 家族的命令:INCRDECR INCRBY 命令即可。
  • 使用 APPEND 命令在 String 末尾追加值
  • 使用 String 实现一个支持随机访问的向量,结合 GETRANGESETRANGE 命令即可。
  • 使用少量空间来编码大量数据,或者创建一个基于 Redis 的布隆过滤器,结合 GETBITSETBIT 命令即可。

你可以查看 所有可用于 String 的命令 来了解更多。

List

Redis 的 List 就是一个 String 列表而已,它根据插入顺序排序。若要往 List 中插入数据,你即可以把数据添加到头部(左边),也可以把数据添加到尾部(右边)。

LPUSH 命令用于添加数据到 List 左边,对应地,RPUSH 用于在 List 右边添加数据。当你对空 key 执行这两个命令时,你实际上就是在创建一个新 List,并给它添加了个 String 值。相似地,当你从一个大小为 1 的 List 中移除数据时,你其实就是在清空它。这是一个很方便的语法,因为当你调用 List 命令,而提供的参数 key 不存在时,你会像是在操作一个空 List,得到符合逻辑的结果。

下面是一些 List 命令和它们的结果:

LPUSH mylist a   # 此时 mylist 的内容为 "a"
LPUSH mylist b   # 此时 mylist 的内容为 "b","a"
RPUSH mylist c   # 此时 mylist 的内容为 "b","a","c",因为使用的是 RPUSH

List 的最大长度为 232 - 1,也就是说,每个 List 的最多可容纳超过 40 亿个元素(String)。

从时间复杂度的角度来看,即使 List 中有数百万个元素,Redis 的 List 在头尾插入和删除也只耗费常数时间而已。访问接近头尾的元素是非常高效的,然而访问中间的元素的需要耗费 O(N) 的时间,其中 N 是 List 的长度。

你可以使用 Redis 的 List 实现很多有意思的功能,比如你可以:

  • 实现社交媒体的时间轴功能,使用 LPUSH 添加新元素到用户时间轴中,然后使用 LRANGE 来取出一些最近插入的元素。
  • 你可以结合使用 LPUSH 和 LTRIM 来创建一个容量为 N 的 List,并且这个 List 只会储存最近添加的 N 个元素。
  • List 可以用来作为消息传递原语。比如,有一个用于创建后台任务的 Ruby 库叫做 Resque
  • 你可以利用 List 做很多事,它支持很多命令,包括 BLPOP 等阻塞命令。

你可以查看 所有可用于 List 的命令 来了解更多。

Set

Redis 的 Set 是无序的 String 集合。它支持在 O(1) 的时间内执行添加元素、删除元素和检查元素是否存在等操作。O(1) 也就是说时间复杂度和 Set 的大小无关。

Redis 的 Set 中不会有重复的元素。往 Set 中多次插入同一个元素,最终结果相当于只插入了一次。也就是说,在往 Set 中添加元素时,不需要预先检查元素是否存在。

有趣的是,Set 支持很多服务端操作,它支持 Set 的计算。你可以对 Set 做并集、交集、差集等计算,它们只会耗费很少的时间。

Set 的最大容量和 List 相同,也是 232 - 1,也就是超过 40 亿。

你可以使用 Redis 的 Set 实现很多有意思的功能,比如你可以:

  • 使用 Set 维护一些唯一的值。比如,你想知道访问某篇博客的所有不同 IP 吗?只需要在处理每次页面访问时,使用 SADD 把访客 IP 添加至 Set 中即可。这样一来,你会得到一个天然去重的 IP 集合。
  • Set 可以很好地表示关系。你可以使用不同 Set 来代表不同标签,接着,你可以使用 SADD 命令把所有标签相同的对象 ID 添加到它对应的 Set 中。你想要让每个对象同时拥有三个标签吗?只要使用 SINTER 就行了。
  • 你可以使用 Set 来随机取元素,使用 SPOPSRANDNUMBER 命令即可。

同样,你可以查看 所有可用于 Set 的命令 来了解更多。

Hash

Redis 的 Hash 是一个 map,map 中每个键值对都是 String 类型,所以它很适合用来表示对象。比如说,可以用它来表示一个“用户”,拥有“名字”、“年龄”等属性,就像下面这样:

HMSET user:1000 username antirez password P1pp0 age 34
HGETALL user:1000
HSET user:1000 password 12345
HGETALL user:1000

一个 Hash 可以有很多属性(最多 100 个左右),但它仅占用很少的空间,所以你可以在一个很小的 Redis 实例中储存几百万个对象(Hash)。

虽然说 Hash 主要是用来表示对象,但它也可以储存很多元素,因此它也用处多多。

每个 Hash 最多可以存 232 - 1(超过 40 亿)个键值对。

你可以查看 所有可用于 Hash 的命令 来了解更多。

Sorted Set

Redis 的 Sorted Set 与 Set 一样,也是一个无重复的 String 集合。它们的不同之处就在于,Sorted Set 的每一个成员都和一个分数score,它会根据这个分数来维持成员从小到大的顺序。每个成员都是不同的,但它们的分数可能会一样。

对于 Sorted Set,你可以执行添加、删除或更新元素等操作,它们都十分高效,时间复杂度为 O(log(N))。由于元素是按序存储的,因此你可以高效地根据分数或位置来获取一个范围。即使是访问中间的元素也是很快的,因此你可以把 Sorted Set 作为一个无重复元素的列表:你可以快速访问任何元素,无论是按序反问、检查元素是否存在还是访问中间的元素!

简而言之,对于 Sorted Set,你可以用它来完成非常多的任务,并且获得极佳性能,而这在其他数据库中是很难达到的。

你可以使用 Redis 的 Sorted Set 实现很多有意思的功能,比如你可以:

  • 实现一个大型在线游戏的排行榜,每当玩家提交分数,你就使用 ZADD 把它加入到 Sorted Set 中。你可以使用 ZRANGE 很轻松地获取名列前茅的用户。或者,给定一个用户名,你也可以使用 ZRANK 获得他的当前排名。结合使用 ZRANKZRANGE,你还可以实现获取“和指定用户分数相近的所有用户”的列表。所有操作都十分高效。
  • Sorted Set 通常用于给 Redis 中的数据添加索引。举个例子,假设你有很多的 Hash 来表示很多的用户,你可以把用户的年龄作为分数,把用户 ID 作为 value,建立一个 Sorted Set。这样,只要使用 ZRANGEBYSCORE,并给定年龄范围,你就可以快速得到所有符合条件的用户。

Sorted Set 是一种比较高级的 Redis 数据类型,因此,你可以查看 所有可用于 Sorted Set 的命令 来了解更多。

Bitmap 和 HyperLogLog

Bitmap 和 HyperLogLog 其实是基于 Stirng 的数据类型,但是它们拥有独特的语义。

(省略)

Stream

Redis 的 Stream 是一种类似仅追加日志的数据结构。Stream 适用于按照出现顺序记录事件。你可以阅读 Redis streams 文档 来了解更多细节和使用。

Geospatial index

Redis 提供 地理空间索引Geospatial index,它对于查找给定半径的地理位置很有用。你可以使用 GEOADD 命令来往地理空间索引中添加位置。接着,你可以使用 GEORADIUS 命令来搜索给定半径内的位置。

你可以阅读 地理空间索引的完整命令参考 来了解它的全部细节。

后语

下一篇文章中,我将介绍如何使用 Redis 的发布/订阅功能。保持关注喔!

参考


本文使用 CC BY-SA 4.0 国际协议 进行许可,欢迎 遵照协议规定 转载。
作者:六开箱
链接:https://lkxed.github.io/posts/redis-data-types-brief/