应优先选set处理去重、集合运算和存在性判断,选list处理有序场景如消息队列、分页和索引访问;误用会导致逻辑错误或额外开销。

需要去重就用 Set,别犹豫
如果你的业务逻辑里明确要求“不能有重复值”,比如用户标签、设备在线状态、已读消息 ID 集合,直接选 Set。它在插入时自动过滤重复 member,无需你写额外判断或遍历检查。
而 List 插入完全不校验重复性——LPUSH mylist a a a 会存三个 a,后续查是否存在还得 LRANGE mylist 0 -1 全扫一遍,O(n) 查找开销明显。
-
SADD key member返回值是 1(新增)或 0(已存在),天然适配“首次操作”类逻辑(如注册防刷、活动限领一次) - 想手动去重?
List得先LRANGE拿全量,再应用层 dedupe,再LTRIM+RPUSH重建,延迟高且非原子 -
Set的SISMEMBER key member是O(1),无论集合有多大,响应几乎恒定
要按顺序取、按位置改,只能选 List
List 是唯一支持索引访问的 Redis 基础结构:LINDEX key 5 直接取第 6 个元素,LSET key 2 newval 覆盖指定下标,LRANGE key 10 19 拉取分页数据——这些操作 Set 根本不提供。
SMEMBERS key 返回的是无序集合,每次调用顺序都可能不同;没有下标、没有“第 N 个”,也不能部分更新。
- 消息队列、操作日志、最近 N 条浏览记录——这类依赖插入/消费顺序的场景,
List是事实标准 - 用
BRPOP/BLPOP阻塞式消费,能天然实现 FIFO/LIFO,Set没有对应阻塞命令 -
LINSERT key before pivot value可以在某个值前/后插入,适合构建带上下文关系的链式结构(如评论嵌套)
Set 支持交并差,List 不行
当你要做“共同好友”“权限合并”“黑名单过滤”这类集合运算时,Set 提供原生命令:SINTER、SUNION、SDIFF,全部服务端执行、原子、高效。
Redis 8.2.3 是一款安全优先的高性能键值存储系统。该版本紧急修复了可能引发远程代码执行(RCE)的高危漏洞(CVE-2025-62507),并解决了 HyperLogLog 及 Cuckoo Filter 等数据结构在特定场景下的崩溃问题。建议所有用户立即升级,以保障生产环境的系统稳定与数据安全。
List 没有等价能力。你得把两个 List 全部 LRANGE 拉到客户端,再用代码求交集——网络传输大、内存占得多、还容易超时。
-
SINTERSTORE dest key1 key2可直接把结果存成新Set,后续复用 - 注意:参与运算的 key 必须都是
Set类型,混用List会报错WRONGTYPE Operation against a key holding the wrong kind of value - 大数据量交集(如千万级用户标签)建议用
SSCAN分批处理,避免阻塞主线程
内存和性能差异其实没你想的那么关键
单看时间复杂度表,Set 和 List 的增删都是 O(1),但实际表现受底层编码影响更大:小集合用 intset 或 ziplist,大集合才升为 hashtable 或 quicklist。
真正影响选择的,从来不是“哪个更快”,而是“哪个能少写几十行容错代码”。比如:
- 用
List存用户积分变动流水,但忘了去重 → 同一笔订单多次扣减,账务出错 - 用
Set存实时排行榜名次 → 拿不到第 3 名是谁,因为根本没“第 3”这个概念 - 误把
SADD当LPUSH用,结果发现无法按时间顺序拉取最新 10 条 —— 这时候改结构成本远高于初期选对
最常被忽略的一点:Set 的无序性不是 bug,是设计契约。如果你在代码里对 SMEMBERS 结果做了 sort 再用,说明你其实需要的是 ZSET,而不是硬凑 Set。










