Redis的set和zset类及主要指令

文章目录

  • Redis的set和zset类及主要指令
    • 一、Set(集合)
      • [1. Set的特点](#1. Set的特点)
      • [2. 内部实现](#2. 内部实现)
      • [3. 常用命令](#3. 常用命令)
        • [3.1 SADD](#3.1 SADD)
        • [3.2 SREM](#3.2 SREM)
        • [3.3 SMEMBERS](#3.3 SMEMBERS)
        • [3.4 SISMEMBER](#3.4 SISMEMBER)
        • [3.5 SCARD](#3.5 SCARD)
        • [3.6 SPOP](#3.6 SPOP)
        • [3.7 SRANDMEMBER](#3.7 SRANDMEMBER)
        • [3.8 SMOVE](#3.8 SMOVE)
        • [3.9 SINTER](#3.9 SINTER)
        • [3.10 SUNION](#3.10 SUNION)
        • [3.11 SDIFF](#3.11 SDIFF)
        • [3.12 交集/并集/差集的 STORE 版本](#3.12 交集/并集/差集的 STORE 版本)
        • [3.13 SSCAN](#3.13 SSCAN)
    • 二、ZSet(有序集合)
      • [1. ZSet的特点](#1. ZSet的特点)
      • [2. 内部实现](#2. 内部实现)
      • [3. 常用命令](#3. 常用命令)
        • [3.1 ZADD](#3.1 ZADD)
        • [3.2 ZREM](#3.2 ZREM)
        • [3.3 ZSCORE](#3.3 ZSCORE)
        • [3.4 ZRANK / ZREVRANK](#3.4 ZRANK / ZREVRANK)
        • [3.5 ZCARD](#3.5 ZCARD)
        • [3.6 ZRANGE](#3.6 ZRANGE)
        • [3.7 ZREVRANGE(仍可用,建议用 ZRANGE ... REV 代替)](#3.7 ZREVRANGE(仍可用,建议用 ZRANGE ... REV 代替))
        • [3.8 ZRANGEBYSCORE / ZREVRANGEBYSCORE](#3.8 ZRANGEBYSCORE / ZREVRANGEBYSCORE)
        • [3.9 ZINCRBY](#3.9 ZINCRBY)
        • [3.10 ZCOUNT](#3.10 ZCOUNT)
        • [3.11 ZREMRANGEBYRANK](#3.11 ZREMRANGEBYRANK)
        • [3.12 ZREMRANGEBYSCORE](#3.12 ZREMRANGEBYSCORE)
        • [3.13 ZPOPMIN / ZPOPMAX](#3.13 ZPOPMIN / ZPOPMAX)
        • [3.14 ZSCAN](#3.14 ZSCAN)
        • [3.15 ZINTER / ZUNION(Redis 6.2+)](#3.15 ZINTER / ZUNION(Redis 6.2+))
    • [三、小结:Set 和 ZSet 的核心差异](#三、小结:Set 和 ZSet 的核心差异)

Redis的set和zset类及主要指令

一、Set(集合)

1. Set的特点

  • 无序:集合里的元素没有先后顺序,不能通过下标访问
  • 唯一:集合里的元素不会重复,同一个元素插多次也只保留一份
  • 支持集合间的交、并、差运算,适合做共同好友、标签聚合这类场景

2. 内部实现

编码 说明
intset(整数集合) 元素全是整数且数量较少时使用,内存连续,查找用二分,O(log n)
hashtable(哈希表) 元素不全是整数或数量超过阈值时使用,也就是只用键、值都设为 NULL 的哈希表

什么时候 intset 会转成 hashtable?

  1. 插入了非整数的元素
  2. 元素数量超过 set-max-intset-entries(默认 512)

这个转换是单向的,就算后来把非整数元素删了,也不会再降回 intset。所以如果确认集合里全是整数且数量可控,intset 能省不少内存。

3. 常用命令

3.1 SADD

往集合里添加元素。已经存在的元素会被忽略,不会报错。

  • 语法

    SADD key member [member ...]

  • 返回值:实际新增的元素个数(已存在的元素不算)

  • 示例

    redis> SADD colors "red"
    (integer) 1
    redis> SADD colors "blue" "green"
    (integer) 2
    redis> SADD colors "red"
    (integer) 0
    redis> SMEMBERS colors

    1. "blue"
    2. "green"
    3. "red"

注意返回值的含义:第一次 SADD "red" 返回 1,因为确实新增了;第二次再 SADD "red" 返回 0,说明它已经在集合里了,不是报错,只是没干事。

3.2 SREM

从集合里移除元素。元素不存在也不会报错。

  • 语法

    SREM key member [member ...]

  • 返回值:实际移除的元素个数(不存在的元素不算)

  • 示例

    redis> SADD colors "red" "blue" "green"
    (integer) 3
    redis> SREM colors "blue" "yellow"
    (integer) 1
    redis> SMEMBERS colors

    1. "green"
    2. "red"

上面 "yellow" 本来就不在集合里,所以 SREM 返回 1(只删了 "blue"),不是 2。

3.3 SMEMBERS

返回集合里所有的元素。注意:集合本身是无序的,所以每次返回的顺序不一定一样。

  • 语法

    SMEMBERS key

  • 返回值:所有元素的列表,key 不存在时返回空列表

  • 示例

    redis> SADD colors "red" "blue" "green"
    (integer) 3
    redis> SMEMBERS colors

    1. "blue"
    2. "green"
    3. "red"

**⚠️ 注意:**SMEMBERS 跟 hash 里的 HGETALL 一样,属于"重"操作。如果集合里有几十上百万个元素,一次性全拉出来会阻塞 Redis。大集合遍历请用 SSCAN 分批次拿。

3.4 SISMEMBER

判断某个元素是不是在集合里。

  • 语法

    SISMEMBER key member

  • 返回值:1 表示存在,0 表示不存在(包括 key 不存在的情况)

  • 示例

    redis> SADD colors "red" "blue"
    (integer) 2
    redis> SISMEMBER colors "red"
    (integer) 1
    redis> SISMEMBER colors "green"
    (integer) 0
    redis> SISMEMBER nonexist "red"
    (integer) 0

3.5 SCARD

返回集合里的元素个数。相当于集合版的 LLEN。

  • 语法

    SCARD key

  • 返回值:集合的基数(元素数量),key 不存在时返回 0

  • 示例

    redis> SADD colors "red" "blue" "green"
    (integer) 3
    redis> SCARD colors
    (integer) 3
    redis> SCARD nonexist
    (integer) 0

3.6 SPOP

随机从集合里弹出一个(或多个)元素,弹出后会从集合中删除。这跟 list 的 LPOP/RPOP 不一样------list 是从固定方向弹,set 是随机弹。

  • 语法

    SPOP key [count]

  • 返回值:弹出的元素(或元素列表),key 不存在 / 空集合返回 nil

  • 示例

    redis> SADD colors "red" "blue" "green" "yellow"
    (integer) 4
    redis> SPOP colors
    "blue"
    redis> SPOP colors 2

    1. "yellow"
    2. "red"
      redis> SMEMBERS colors
    3. "green"

Redis 3.2 之后支持传 count 参数,一次随机弹出多个。count 不能为负数。

3.7 SRANDMEMBER

随机返回集合里的元素,但不删除。SPOP 是"拿走",SRANDMEMBER 是"看看"。

  • 语法

    SRANDMEMBER key [count]

  • 返回值:不传 count 返回一个元素;传了返回列表

  • 示例

    redis> SADD colors "red" "blue" "green"
    (integer) 3
    redis> SRANDMEMBER colors
    "green"
    redis> SRANDMEMBER colors 2

    1. "blue"
    2. "green"
      redis> SRANDMEMBER colors -3
    3. "green"
    4. "green"
    5. "blue"

count 参数跟 HRANDFIELD 一样:

  • count 为正:返回的元素不重复,最多返回整个集合
  • count 为负:返回的元素可能重复,凑够 |count| 个为止
3.8 SMOVE

把某个元素从源集合移动到目标集合。这是一个原子操作------要么两端都成功,要么都不动。

  • 语法

    SMOVE source destination member

  • 返回值:1 表示移动成功,0 表示源集合里没有这个元素

  • 示例

    redis> SADD set1 "a" "b" "c"
    (integer) 3
    redis> SADD set2 "d" "e"
    (integer) 2
    redis> SMOVE set1 set2 "b"
    (integer) 1
    redis> SMEMBERS set1

    1. "a"
    2. "c"
      redis> SMEMBERS set2
    3. "b"
    4. "d"
    5. "e"
      redis> SMOVE set1 set2 "x"
      (integer) 0

如果目标集合已经存在这个元素,SMOVE 也只会把源集合里的删掉,目标集合不会出现重复(集合本来就不允许重复)。

3.9 SINTER

求多个集合的交集,返回同时出现在所有集合里的元素。

  • 语法

    SINTER key [key ...]

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

  • 示例

    redis> SADD set1 "a" "b" "c"
    (integer) 3
    redis> SADD set2 "b" "c" "d"
    (integer) 3
    redis> SADD set3 "b" "c" "e"
    (integer) 3
    redis> SINTER set1 set2 set3

    1. "b"
    2. "c"
3.10 SUNION

求多个集合的并集,把所有集合的元素合在一起,自动去重。

  • 语法

    SUNION key [key ...]

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

  • 示例

    redis> SADD set1 "a" "b" "c"
    (integer) 3
    redis> SADD set2 "d" "e"
    (integer) 2
    redis> SUNION set1 set2

    1. "a"
    2. "b"
    3. "c"
    4. "d"
    5. "e"
3.11 SDIFF

求多个集合的差集,返回在第一个集合里但不在后续集合里的元素。

  • 语法

    SDIFF key [key ...]

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

  • 示例

    redis> SADD set1 "a" "b" "c" "d"
    (integer) 4
    redis> SADD set2 "c" "d" "e"
    (integer) 3
    redis> SDIFF set1 set2

    1. "a"
    2. "b"
      redis> SDIFF set2 set1
    3. "e"

顺序很重要SDIFF A BSDIFF B A 结果完全不同,前者是"在 A 但不在 B",后者是"在 B 但不在 A"。

3.12 交集/并集/差集的 STORE 版本

这三个集合运算都有对应的 STORE 版本,差别是结果不直接返回,而是存到 destination 里。适合中间结果要多次使用的场景,不用每次都重新算。

复制代码
SINTERSTORE destination key [key ...]
SUNIONSTORE destination key [key ...]
SDIFFSTORE destination key [key ...]
  • 返回值:结果集合的元素个数

  • 示例

    redis> SADD set1 "a" "b" "c"
    (integer) 3
    redis> SADD set2 "b" "c" "d"
    (integer) 3
    redis> SINTERSTORE inter set1 set2
    (integer) 2
    redis> SMEMBERS inter

    1. "b"
    2. "c"
3.13 SSCAN

分批次迭代集合里的元素,是遍历大集合的正确姿势。用法跟 SCAN 一样。

  • 语法

    SSCAN key cursor [MATCH pattern] [COUNT count]

  • 返回值:下一轮的游标和当前批次的元素列表。游标返回 0 时表示遍历结束。

  • 示例

    redis> SADD colors "red" "blue" "green" "yellow" "purple" "orange"
    (integer) 6
    redis> SSCAN colors 0 MATCH e COUNT 2

    1. "4"
      1. "purple"
      2. "blue"
        redis> SSCAN colors 4
    2. "0"
      1. "orange"
      2. "green"
      3. "yellow"
      4. "red"

游标不一定连续,不能用 for 循环递增------每次用上一轮返回的游标值就行,0 代表结束。

二、ZSet(有序集合)

1. ZSet的特点

  • 跟 set 一样,member 唯一不重复
  • 但每个 member 关联一个 score(分值),元素按 score 从小到大排列
  • score 可以重复------多个 member 可以有相同的分数,这时候按 member 的字典序排
  • 适合排行榜、延迟队列、带权重的标签这类既要去重又要排序的场景

2. 内部实现

编码 说明
ziplist / listpack 元素少且短时使用,member 和 score 交替紧凑存放,省内存
skiplist(跳表)+ hashtable 数据量大时使用。跳表负责按 score 排序,hashtable 负责 O(1) 查 member 的 score

什么时候切换?

  1. 元素数量超过 zset-max-ziplist-entries(或 zset-max-listpack-entries
  2. 某个 member 的长度超过 zset-max-ziplist-value(或 zset-max-listpack-value

这个切换逻辑跟 hash 是一样的:少量数据用紧凑结构省内存,数据多了切跳表保证查询性能。
为什么需要跳表 + 哈希表一起上?

跳表按 score 范围查很高效(ZRANGE、ZRANGEBYSCORE),但按 member 查 score 的时候得遍历,O(log n) 虽然也不差,但配合一个 hashtable 直接 O(1) 更划算。Redis 是拿空间换时间------反正 hashtable 只存 member→score 的指针,实际数据不存两份,开销没那么大。

3. 常用命令

3.1 ZADD

往有序集合里添加 member 和 score。member 已存在时会更新 score。

  • 语法

    ZADD key [NX|XX] [GT|LT] [CH] [INCR] score member [score member ...]

选项说明:

  • NX:只在 member 不存在时才添加
  • XX:只在 member 存在时才更新
  • GT:只在新 score > 旧 score 时才更新
  • LT:只在新 score < 旧 score 时才更新
  • CH:返回值改成"被修改的元素数"(新增 + 更新都算),默认只统计新增
  • INCR:对 member 的 score 做增量操作,此时只能操作一个 member
  • 返回值:默认返回新增的 member 数;加了 CH 返回变更数;加了 INCR 返回新的 score

  • 示例

    redis> ZADD rank 100 "zhangsan" 80 "lisi" 60 "wangwu"
    (integer) 3
    redis> ZADD rank 90 "lisi"
    (integer) 0
    redis> ZADD rank CH 200 "zhangsan"
    (integer) 1
    redis> ZADD rank NX 70 "lisi"
    (integer) 0

第一个 ZADD 返回 3,三个都是新增。第二个 ZADD 更新了 lisi 的 score,但只算新增所以返回 0。第三个加了 CH 参数,"zhangsan" 的 score 被更新了,算一次变更。第四个 NX 了 "lisi",但它已经存在,不执行,返回 0。

3.2 ZREM

从有序集合里删除 member。

  • 语法

    ZREM key member [member ...]

  • 返回值:实际删除的 member 数

  • 示例

    redis> ZADD rank 100 "zhangsan" 80 "lisi" 60 "wangwu"
    (integer) 3
    redis> ZREM rank "lisi" "zhaoliu"
    (integer) 1
    redis> ZRANGE rank 0 -1

    1. "wangwu"
    2. "zhangsan"
3.3 ZSCORE

返回某个 member 的 score。member 不存在返回 nil。

  • 语法

    ZSCORE key member

  • 返回值:score 的值(字符串格式的浮点数),member 不存在返回 nil

  • 示例

    redis> ZADD rank 100 "zhangsan" 80 "lisi"
    (integer) 2
    redis> ZSCORE rank "zhangsan"
    "100"
    redis> ZSCORE rank "wangwu"
    (nil)

3.4 ZRANK / ZREVRANK

ZRANK 返回 member 在有序集合中的升序排名(从 0 开始,score 最小的排第 0)。ZREVRANK 相反,按 score 降序排名(score 最大的排第 0)。

  • 语法

    ZRANK key member
    ZREVRANK key member

  • 返回值:排名,member 不存在返回 nil

  • 示例

    redis> ZADD rank 100 "zhangsan" 80 "lisi" 60 "wangwu"
    (integer) 3
    redis> ZRANK rank "lisi"
    (integer) 1
    redis> ZREVRANK rank "lisi"
    (integer) 1

"lisi" 的 score=80,升序排第二(0: wangwu/60, 1: lisi/80, 2: zhangsan/100),降序也排第二(0: zhangsan/100, 1: lisi/80, 2: wangwu/60)。

3.5 ZCARD

返回有序集合里的元素个数。

  • 语法

    ZCARD key

  • 返回值:member 数量,key 不存在返回 0

  • 示例

    redis> ZADD rank 100 "zhangsan" 80 "lisi" 60 "wangwu"
    (integer) 3
    redis> ZCARD rank
    (integer) 3

3.6 ZRANGE

按 score 升序返回指定下标范围的 member。默认只返回 member,加 WITHSCORES 同时返回 score。

  • 语法

    ZRANGE key start stop [BYSCORE | BYLEX] [REV] [LIMIT offset count] [WITHSCORES]

  • 返回值:member 的列表(带 WITHSCORES 时 member、score 交替)

  • 示例

    redis> ZADD rank 100 "zhangsan" 80 "lisi" 60 "wangwu"
    (integer) 3
    redis> ZRANGE rank 0 -1

    1. "wangwu"
    2. "lisi"
    3. "zhangsan"
      redis> ZRANGE rank 0 -1 WITHSCORES
    4. "wangwu"
    5. "60"
    6. "lisi"
    7. "80"
    8. "zhangsan"
    9. "100"
      redis> ZRANGE rank 0 0
    10. "wangwu"

Redis 6.2 之后 ZRANGE 功能更丰富了:加了 REV 的效果跟 ZREVRANGE 一样,加了 BYSCORE 就跟 ZRANGEBYSCORE 一样,加了 BYLEX 就跟 ZRANGEBYLEX 一样。不过为了兼容老代码,旧的 ZREVRANGE、ZRANGEBYSCORE 这些命令依然能用。

3.7 ZREVRANGE(仍可用,建议用 ZRANGE ... REV 代替)

按 score 降序返回指定下标范围的 member。

  • 语法

    ZREVRANGE key start stop [WITHSCORES]

  • 返回值:member 列表

  • 示例

    redis> ZADD rank 100 "zhangsan" 80 "lisi" 60 "wangwu"
    (integer) 3
    redis> ZREVRANGE rank 0 -1 WITHSCORES

    1. "zhangsan"
    2. "100"
    3. "lisi"
    4. "80"
    5. "wangwu"
    6. "60"
3.8 ZRANGEBYSCORE / ZREVRANGEBYSCORE

按 score 范围过滤 member。ZRANGEBYSCORE 是升序,ZREVRANGEBYSCORE 是降序。支持开闭区间。

  • 语法

    ZRANGEBYSCORE key min max [WITHSCORES] [LIMIT offset count]
    ZREVRANGEBYSCORE key max min [WITHSCORES] [LIMIT offset count]

( 表示开区间:(80 表示 score > 80,不包括 80

-inf+inf 表示负无穷和正无穷

ZREVRANGEBYSCORE 写的是 max 在前 min 在后,因为它从大到小排

  • 返回值:满足条件的 member 列表

  • 示例

    redis> ZADD rank 100 "zhangsan" 80 "lisi" 60 "wangwu" 90 "zhaoliu"
    (integer) 4
    redis> ZRANGEBYSCORE rank 70 100

    1. "lisi"
    2. "zhaoliu"
    3. "zhangsan"
      redis> ZRANGEBYSCORE rank (80 100
    4. "zhaoliu"
    5. "zhangsan"
      redis> ZRANGEBYSCORE rank -inf +inf
    6. "wangwu"
    7. "lisi"
    8. "zhaoliu"
    9. "zhangsan"
      redis> ZRANGEBYSCORE rank 70 100 LIMIT 1 2
    10. "zhaoliu"
    11. "zhangsan"
      redis> ZREVRANGEBYSCORE rank 100 70
    12. "zhangsan"
    13. "zhaoliu"
    14. "lisi"
3.9 ZINCRBY

把 member 的 score 加上一个增量。member 不存在就当它 score 为 0 再加。

  • 语法

    ZINCRBY key increment member

  • 返回值:加完后的 score

  • 示例

    redis> ZADD rank 100 "zhangsan" 80 "lisi"
    (integer) 2
    redis> ZINCRBY rank 10 "lisi"
    "90"
    redis> ZINCRBY rank 200 "wangwu"
    "200"
    redis> ZINCRBY rank -15 "zhangsan"
    "85"

排行榜场景里 ZINCRBY 很实用------用户得分变化时直接调用就完了,不用先 ZSCORE 拿到旧值再加回去,一步到位。

3.10 ZCOUNT

统计 score 在指定区间里的 member 个数。

  • 语法

    ZCOUNT key min max

  • 返回值:符合条件的 member 数量

  • 示例

    redis> ZADD rank 100 "zhangsan" 80 "lisi" 60 "wangwu" 90 "zhaoliu"
    (integer) 4
    redis> ZCOUNT rank 70 100
    (integer) 3
    redis> ZCOUNT rank (80 100
    (integer) 2

3.11 ZREMRANGEBYRANK

按排名范围删除 member。下标从 0 开始。

  • 语法

    ZREMRANGEBYRANK key start stop

  • 返回值:删除的 member 个数

  • 示例

    redis> ZADD rank 100 "zhangsan" 80 "lisi" 60 "wangwu" 90 "zhaoliu"
    (integer) 4
    redis> ZREMRANGEBYRANK rank 0 1
    (integer) 2
    redis> ZRANGE rank 0 -1

    1. "zhaoliu"
    2. "zhangsan"
3.12 ZREMRANGEBYSCORE

按 score 范围删除 member。

  • 语法

    ZREMRANGEBYSCORE key min max

  • 返回值:删除的 member 个数

  • 示例

    redis> ZADD rank 100 "zhangsan" 80 "lisi" 60 "wangwu" 90 "zhaoliu"
    (integer) 4
    redis> ZREMRANGEBYSCORE rank 60 80
    (integer) 2
    redis> ZRANGE rank 0 -1

    1. "zhaoliu"
    2. "zhangsan"
3.13 ZPOPMIN / ZPOPMAX

弹出 score 最小(或最大)的 member。可以一次弹出多个。

  • 语法

    ZPOPMIN key [count]
    ZPOPMAX key [count]

  • 返回值:弹出 member 和 score 的交替列表

  • 示例

    redis> ZADD rank 100 "zhangsan" 80 "lisi" 60 "wangwu"
    (integer) 3
    redis> ZPOPMIN rank

    1. "wangwu"
    2. "60"
      redis> ZPOPMAX rank 2
    3. "zhangsan"
    4. "100"
    5. "lisi"
    6. "80"

ZPOPMIN/ZPOPMAX 在 Redis 5.0 引入。做简单的延迟队列或者任务调度时很好用------比如用 score 存时间戳,ZPOPMIN 弹出最早该执行的任务。

3.14 ZSCAN

跟 SSCAN 一样,分批次迭代有序集合。返回 member 和 score 交替排列。

  • 语法

    ZSCAN key cursor [MATCH pattern] [COUNT count]

  • 返回值:下一轮游标和当前批次的 member-score 列表

  • 示例

    redis> ZADD rank 100 "zhangsan" 80 "lisi" 60 "wangwu"
    (integer) 3
    redis> ZSCAN rank 0

    1. "0"
      1. "wangwu"
      2. "60"
      3. "lisi"
      4. "80"
      5. "zhangsan"
      6. "100"
3.15 ZINTER / ZUNION(Redis 6.2+)

有序集合的交集和并集。比直接使用 ZINTERSTORE/ZUNIONSTORE 多了"直接返回结果"的选项。

  • 语法

    ZINTER numkeys key [key ...] [WEIGHTS weight [weight ...]] [AGGREGATE SUM|MIN|MAX] [WITHSCORES]
    ZUNION numkeys key [key ...] [WEIGHTS weight [weight ...]] [AGGREGATE SUM|MIN|MAX] [WITHSCORES]

参数说明:

  • WEIGHTS:每个集合的权重,做运算前会把 score 先乘上对应权重
  • AGGREGATE:多个集合里相同 member 的 score 怎么合并。SUM 求和(默认)、MIN 取最小、MAX 取最大
  • 示例

    redis> ZADD z1 10 "a" 20 "b"
    (integer) 2
    redis> ZADD z2 5 "a" 15 "c"
    (integer) 2
    redis> ZINTER 2 z1 z2

    1. "a"
      redis> ZINTER 2 z1 z2 WITHSCORES
    2. "a"
    3. "15"
      redis> ZINTER 2 z1 z2 WEIGHTS 2 3 WITHSCORES
    4. "a"
    5. "35"
      redis> ZUNION 2 z1 z2 AGGREGATE MAX WITHSCORES
    6. "a"
    7. "10"
    8. "b"
    9. "20"
    10. "c"
    11. "15"

上面 ZINTER 里 "a" 的 score 是 15,因为默认 AGGREGATE 是 SUM:10 × 1 + 5 × 1 = 15。加了 WEIGHTS 2 3 之后:10 × 2 + 5 × 3 = 35。ZUNION 跟的是 MAX 策略,各 member 取最大的 score。

三、小结:Set 和 ZSet 的核心差异

维度 Set(集合) ZSet(有序集合)
有没有顺序 无序,遍历顺序不稳定 按 score 升序排列,score 相同按字典序
元素组成 只有 member member + score,score 是双精度浮点数
唯一性 member 唯一 member 唯一,但 score 可以重复
内部编码 intset / hashtable listpack(ziplist) / skiplist + hashtable
典型场景 标签、共同好友、去重、随机抽奖 排行榜、延迟队列、按时间排序的 feed
核心操作 交/并/差集(SINTER/SUNION/SDIFF) 按 score 范围查(ZRANGEBYSCORE)、按排名查(ZRANK)
内存占用 相对小,纯整数场景下 intset 非常省 稍大,跳表指针 + hashtable 有额外开销

总结:

如果只需要"有没有"(去重、标签、交集),用 Set;

如果还需要"谁排前面"(排行榜、优先级、时间线),用 ZSet。

两者的选择说到底就是一个问题:要不要排序。不要排序就 Set,要排序就 ZSet。ZSet 多出来的那个 score,本质上就是排序用的"权重",没了它 ZSet 跟 Set 做的事差不多。

相关推荐
Steadfast_GG3 小时前
Redis典型应用 - 缓存,缓存更新策略,内存淘汰策略,缓存预热,缓存穿透,缓存雪崩,缓存击穿
redis·缓存穿透·缓存击穿·缓存雪崩·缓存预热·缓存更新策略·内存淘汰策略
snow@li8 小时前
Redis:数据库语法速查表 / 全景梳理
数据库·redis·缓存
云技纵横14 小时前
Redis 延迟双删还是读到脏数据?一次缓存一致性事故
redis·后端·面试
AskHarries15 小时前
Redis 应该什么时候上
redis
桑榆肖物16 小时前
在 .NET MAUI 里接入 PP-OCRv6 文本检测实现查找并点击
数据库·redis·.net·maui
手握风云-16 小时前
Redis:不只是缓存那么简单(十四)
redis·缓存
ffqws_1 天前
Redis 分布式锁:基于 Redisson 的实现与面试高频问答
redis·分布式·面试
Leighteen1 天前
Redis与MySQL双写一致性:从问题根源到工程落地
数据库·redis·mysql
手握风云-1 天前
Redis:不只是缓存那么简单(十五)
数据库·redis·缓存