本文简单介绍了 Redis 支持的诸多数据类型。
前言
Redis 支持许多数据类型,尽管我们使用最多的仍然是 String。诚然,在大多数场景下,String 似乎都能够解决我们的问题,最多在程序中多几次转换而已。但是,Redis 提供的强大类型可以让我们省去许多复杂的逻辑,更重要的是,它总是会比我们自己实现有着更高的效率,不是吗?
String
String 是最基础的 Redis 数据类型。Redis 的 String 是二进制安全的,这意味着它可以储存任何种类的数据,例如 JPEG 图片或序列化的 Ruby 对象。
String 值支持的最大长度是 512 MB。
你可以使用 Redis 的 String 实现很多有意思的功能,比如你可以:
- 使用 String 实现一个原子计数器,结合 INCR 家族的命令:
INCR
、DECR
和INCRBY
命令即可。 - 使用
APPEND
命令在 String 末尾追加值 - 使用 String 实现一个支持随机访问的向量,结合
GETRANGE
和SETRANGE
命令即可。 - 使用少量空间来编码大量数据,或者创建一个基于 Redis 的布隆过滤器,结合
GETBIT
和SETBIT
命令即可。
你可以查看 所有可用于 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 来随机取元素,使用
SPOP
和SRANDNUMBER
命令即可。
同样,你可以查看 所有可用于 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 的每一个成员都和一个分数,它会根据这个分数来维持成员从小到大的顺序。每个成员都是不同的,但它们的分数可能会一样。
对于 Sorted Set,你可以执行添加、删除或更新元素等操作,它们都十分高效,时间复杂度为 O(log(N))。由于元素是按序存储的,因此你可以高效地根据分数或位置来获取一个范围。即使是访问中间的元素也是很快的,因此你可以把 Sorted Set 作为一个无重复元素的列表:你可以快速访问任何元素,无论是按序反问、检查元素是否存在还是访问中间的元素!
简而言之,对于 Sorted Set,你可以用它来完成非常多的任务,并且获得极佳性能,而这在其他数据库中是很难达到的。
你可以使用 Redis 的 Sorted Set 实现很多有意思的功能,比如你可以:
- 实现一个大型在线游戏的排行榜,每当玩家提交分数,你就使用
ZADD
把它加入到 Sorted Set 中。你可以使用ZRANGE
很轻松地获取名列前茅的用户。或者,给定一个用户名,你也可以使用ZRANK
获得他的当前排名。结合使用ZRANK
和ZRANGE
,你还可以实现获取“和指定用户分数相近的所有用户”的列表。所有操作都十分高效。 - 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 提供 地理空间索引,它对于查找给定半径的地理位置很有用。你可以使用 GEOADD
命令来往地理空间索引中添加位置。接着,你可以使用 GEORADIUS
命令来搜索给定半径内的位置。
你可以阅读 地理空间索引的完整命令参考 来了解它的全部细节。
后语
下一篇文章中,我将介绍如何使用 Redis 的发布/订阅功能。保持关注喔!
参考
本文使用 CC BY-SA 4.0 国际协议 进行许可,欢迎 遵照协议规定 转载。
作者:六开箱
链接:https://lkxed.github.io/posts/redis-data-types-brief/