Redis Set:原理、命令与实战场景详解

Redis 数据结构精讲:Set 集合的原理、命令与实战场景

大家好,今天我们来聊聊 Redis 中一个非常实用的数据结构 ------Set(集合) 。它和我们熟悉的列表(List)有很多相似之处,比如都能存储多个字符串类型的元素,但也有几个关键区别:Set 中的元素是无序 的,而且不允许重复。更重要的是,Redis 的 Set 天生支持交集、并集、差集这些集合操作,在很多业务场景下都能发挥奇效。


一、Set 集合的基本概念

先看个直观的例子,比如我们要记录用户 user:1 的兴趣爱好:

可以看到,Set 的 Key 是 user:1:subscribe,对应的 Value 是一个包含 BasketballITMusic 等多个元素的集合。这些元素没有固定顺序,也不会重复,完美契合了 "用户兴趣标签" 这类场景的需求。


二、Set 集合的基础命令详解

我们先从最常用的基础命令开始,逐个拆解它们的用法、时间复杂度和实战示例。

1. SADD:添加元素到集合

作用:将一个或多个元素添加到集合中,重复元素会被自动忽略。

  • 语法SADD key member [member \.\.\.\]

  • 时间复杂度:O(1)

  • 返回值:本次成功添加的元素个数

redis 复制代码
redis> SADD myset "Hello"
(integer) 1
redis> SADD myset "World"
(integer) 1
redis> SADD myset "World"
(integer) 0  # 重复元素添加失败,返回0
redis> SMEMBERS myset
1) "Hello"
2) "World"

2. SMEMBERS:获取集合中所有元素

作用:返回集合中的所有元素,注意元素的顺序是无序的。

  • 语法SMEMBERS key

  • 时间复杂度:O (N)(N 为集合元素个数)

  • 返回值:集合中所有元素的列表

redis 复制代码
redis> SADD myset "Hello"
(integer) 1
redis> SADD myset "World"
(integer) 1
redis> SMEMBERS myset
1) "Hello"
2) "World"

3. SISMEMBER:判断元素是否存在于集合中

作用:判断一个元素是否是集合的成员。

  • 语法SISMEMBER key member

  • 时间复杂度:O(1)

  • 返回值:1 表示元素存在,0 表示元素不存在或集合本身不存在

redis 复制代码
redis> SADD myset "one"
(integer) 1
redis> SISMEMBER myset "one"
(integer) 1
redis> SISMEMBER myset "two"
(integer) 0

4. SCARD:获取集合的元素个数

作用:获取集合的基数(cardinality),也就是集合中元素的数量。

  • 语法SCARD key

  • 时间复杂度:O(1)

  • 返回值:集合中的元素个数

redis 复制代码
redis> SADD myset "Hello"
(integer) 1
redis> SADD myset "World"
(integer) 1
redis> SCARD myset
(integer) 2

5. SPOP:随机删除并返回元素

作用:从集合中随机删除并返回一个或多个元素(因为集合是无序的,删除的元素是随机的)。

  • 语法SPOP key [count\]

  • 时间复杂度:O (N)(N 为 count 的值)

  • 返回值:被删除的元素

redis 复制代码
redis> SADD myset "one"
(integer) 1
redis> SADD myset "two"
(integer) 1
redis> SADD myset "three"
(integer) 1
redis> SPOP myset
"one"
redis> SMEMBERS myset
1) "two"
2) "three"
redis> SADD myset "four"
(integer) 1
redis> SADD myset "five"
(integer) 1
redis> SPOP myset 3
1) "four"
2) "five"
3) "two"

6. SMOVE:移动元素到另一个集合

作用:将一个元素从源集合移动到目标集合中。

  • 语法SMOVE source destination member

  • 时间复杂度:O(1)

  • 返回值:1 表示移动成功,0 表示元素不存在或移动失败

redis 复制代码
redis> SADD myset "one"
(integer) 1
redis> SADD myset "two"
(integer) 1
redis> SADD myotherset "three"
(integer) 1
redis> SMOVE myset myotherset "two"
(integer) 1
redis> SMEMBERS myset
1) "one"
redis> SMEMBERS myotherset
1) "three"
2) "two"

7. SREM:删除集合中的指定元素

作用:从集合中删除一个或多个指定的元素。

  • 语法SREM key member [member \.\.\.\]

  • 时间复杂度:O (N)(N 为要删除的元素个数)

  • 返回值:本次操作成功删除的元素个数

redis 复制代码
redis> SADD myset "one"
(integer) 1
redis> SADD myset "two"
(integer) 1
redis> SADD myset "three"
(integer) 1
redis> SREM myset "one"
(integer) 1
redis> SMEMBERS myset
1) "two"
2) "three"

三、集合间的高级操作:交集、并集、差集

这是 Redis Set 最强大的功能之一,支持多个集合之间的数学运算,比如交集(inter)、并集(union)、差集(diff)。

1. SINTER:获取多个集合的交集

作用:返回所有给定集合的交集元素。

  • 语法SINTER key [key \.\.\.\]

  • 时间复杂度:O (N*M)(N 是最小集合的元素个数,M 是集合的数量)

  • 返回值:交集的元素列表

redis 复制代码
redis> SADD key1 "a"
(integer) 1
redis> SADD key1 "b"
(integer) 1
redis> SADD key1 "c"
(integer) 1
redis> SADD key2 "c"
(integer) 1
redis> SADD key2 "d"
(integer) 1
redis> SADD key2 "e"
(integer) 1
redis> SINTER key1 key2
1) "c"

2. SINTERSTORE:将交集结果保存到目标集合

作用 :和 SINTER 功能类似,但会把交集结果存储到指定的目标集合中,而不是直接返回。

  • 语法SINTERSTORE destination key [key \.\.\.\]

  • 时间复杂度:O(N*M)

  • 返回值:交集中元素的个数

redis 复制代码
redis> SADD key1 "a"
(integer) 1
redis> SADD key1 "b"
(integer) 1
redis> SADD key1 "c"
(integer) 1
redis> SADD key2 "c"
(integer) 1
redis> SADD key2 "d"
(integer) 1
redis> SADD key2 "e"
(integer) 1
redis> SINTERSTORE key key1 key2
(integer) 1
redis> SMEMBERS key
1) "c"

3. SUNION:获取多个集合的并集

作用:返回所有给定集合的并集元素(合并所有元素并去重)。

  • 语法SUNION key [key \.\.\.\]

  • 时间复杂度:O (N)(N 是所有集合元素的总数)

  • 返回值:并集的元素列表

redis 复制代码
redis> SADD key1 "a"
(integer) 1
redis> SADD key1 "b"
(integer) 1
redis> SADD key1 "c"
(integer) 1
redis> SADD key2 "c"
(integer) 1
redis> SADD key2 "d"
(integer) 1
redis> SADD key2 "e"
(integer) 1
redis> SUNION key1 key2
1) "a"
2) "b"
3) "c"
4) "d"
5) "e"

4. SUNIONSTORE:将并集结果保存到目标集合

作用 :和 SUNION 功能类似,但会把并集结果存储到指定的目标集合中。

  • 语法SUNIONSTORE destination key [key \.\.\.\]

  • 时间复杂度:O(N)

  • 返回值:并集中元素的个数

redis 复制代码
redis> SADD key1 "a"
(integer) 1
redis> SADD key1 "b"
(integer) 1
redis> SADD key1 "c"
(integer) 1
redis> SADD key2 "c"
(integer) 1
redis> SADD key2 "d"
(integer) 1
redis> SADD key2 "e"
(integer) 1
redis> SUNIONSTORE key key1 key2
(integer) 5
redis> SMEMBERS key
1) "a"
2) "b"
3) "c"
4) "d"
5) "e"

5. SDIFF:获取多个集合的差集

作用:返回第一个集合与其他集合的差集元素(只保留第一个集合中独有的元素)。

  • 语法SDIFF key [key \.\.\.\]

  • 时间复杂度:O(N)

  • 返回值:差集的元素列表

redis 复制代码
redis> SADD key1 "a"
(integer) 1
redis> SADD key1 "b"
(integer) 1
redis> SADD key1 "c"
(integer) 1
redis> SADD key2 "c"
(integer) 1
redis> SADD key2 "d"
(integer) 1
redis> SADD key2 "e"
(integer) 1
redis> SDIFF key1 key2
1) "a"
2) "b"

6. SDIFFSTORE:将差集结果保存到目标集合

作用 :和 SDIFF 功能类似,但会把差集结果存储到指定的目标集合中。

  • 语法SDIFFSTORE destination key [key \.\.\.\]

  • 时间复杂度:O(N)

  • 返回值:差集中元素的个数

redis 复制代码
redis> SADD key1 "a"
(integer) 1
redis> SADD key1 "b"
(integer) 1
redis> SADD key1 "c"
(integer) 1
redis> SADD key2 "c"
(integer) 1
redis> SADD key2 "d"
(integer) 1
redis> SADD key2 "e"
(integer) 1
redis> SDIFFSTORE key key1 key2
(integer) 2
redis> SMEMBERS key
1) "a"
2) "b"

四、Set 命令速查表

这里整理了所有常用的 Set 命令,方便大家快速查阅:

命令 功能描述 时间复杂度
SADD key member [\.\.\.\] 添加元素到集合 O(1)
SMEMBERS key 获取集合所有元素 O(N)
SISMEMBER key member 判断元素是否存在 O(1)
SCARD key 获取集合元素个数 O(1)
SPOP key [count\] 随机删除并返回元素 O (N)(N 为 count)
SMOVE src dest member 移动元素到另一个集合 O(1)
SREM key member [\.\.\.\] 删除指定元素 O (N)(N 为删除的元素数)
SINTER key1 key2 [\.\.\.\] 获取多个集合的交集 O(N*M)
SINTERSTORE dest key1 [\.\.\.\] 存储交集结果到目标集合 O(N*M)
SUNION key1 key2 [\.\.\.\] 获取多个集合的并集 O(N)
SUNIONSTORE dest key1 [\.\.\.\] 存储并集结果到目标集合 O(N)
SDIFF key1 key2 [\.\.\.\] 获取多个集合的差集 O(N)
SDIFFSTORE dest key1 [\.\.\.\] 存储差集结果到目标集合 O(N)

五、Set 集合的底层编码实现

Redis 的 Set 类型有两种底层编码方式,会根据场景自动切换:

  1. intset(整数集合) :当集合中的元素都是整数,且元素个数不超过 512 个时,Redis 会使用 intset 编码存储,这种方式非常节省内存。

    redis 复制代码
    127.0.0.1:6379> SADD setkey 1 2 3 4
    (integer) 4
    127.0.0.1:6379> OBJECT encoding setkey
    "intset"
  2. hashtable(哈希表) :当集合中的元素包含非整数,或者元素个数超过 512 个时,Redis 会自动切换为 hashtable 编码,以保证读写性能。

    redis 复制代码
    127.0.0.1:6379> SADD setkey 1 2 3 4 ... (添加超过512个元素)
    127.0.0.1:6379> OBJECT encoding setkey
    "hashtable"

六、Set 集合的实战场景

Set 集合的特性,让它在很多业务场景下都能大显身手,这里举几个常见的例子:

1. 给用户添加兴趣标签

我们可以用 Set 存储用户的兴趣标签,天然去重,添加 / 删除都很方便:

redis 复制代码
SADD user:1:tags tag1 tag2 tag3
SADD user:1:tags tag1 tag4  # 重复的tag1会被忽略

2. 给标签添加用户

反过来,也可以用 Set 存储每个标签下的用户列表:

redis 复制代码
SADD tag:1:users user:1 user:2 user:3
SADD tag:2:users user:1 user:4 user:9

3. 计算用户的共同好友 / 共同兴趣

利用 Set 的交集功能,我们可以轻松计算两个用户的共同兴趣标签:

redis 复制代码
# 计算user:1和user:2的共同兴趣
SINTER user:1:tags user:2:tags

这种场景在社交平台、推荐系统中非常常见,比如:

  • 计算两个用户的共同好友

  • 找出同时关注了多个话题的用户

  • 统计用户的共同兴趣,实现个性化推荐


总结

Redis 的 Set 集合虽然结构简单,但功能非常强大:无序、去重、支持丰富的集合运算,在标签系统、好友关系、数据去重等场景中都有不可替代的优势。掌握好这些命令和底层原理,就能在开发中灵活运用,写出更高效、更优雅的代码。

相关推荐
他是龙5511 小时前
SQLi-Labs 通关笔记(Less-38 ~ Less-53):堆叠注入与 ORDER BY 注入
数据库·笔记·less
今天也是元气满满的一天呢1 小时前
20260512-SQL学习大览
数据库·sql·学习
北秋,1 小时前
Web Security Academy 第二关:SQL 注入登录绕过
数据库·sql
思麟呀1 小时前
MySQL基础CRUD语句
数据库·mysql
funnycoffee1231 小时前
cisco Firepower 4110 9300 FXOS set chassis hostname
java·服务器·数据库
六月雨滴1 小时前
Oracle 数据库诊断文件与故障排查
数据库
草莓熊Lotso1 小时前
【Linux网络】从 0 到 1 实现高性能 UDP 聊天室:深入拆解 Linux 网络编程与线程池架构
linux·运维·服务器·网络·数据库·c++·udp
咖啡里的茶i1 小时前
实验一 数据库定义
数据库·oracle
IT 行者1 小时前
Qdrant vs Milvus 向量数据库对比选型指南
数据库·milvus·qdrant