Skip to content

Redis 中 Sorted Set(有序集合)类型

Redis的Sorted Set是一种有序且元素唯一的数据结构,每个元素关联一个分数(score),实现按分数排序和高效范围查询。

  1. 底层实现
    • ziplist(压缩列表):元素较少时,使用连续内存存储(元素和分数交替排列),节省内存。
    • 跳跃表(skiplist) + 哈希表:默认实现方式,跳跃表支持快速范围操作,哈希表保证元素唯一性并实现O(1)复杂度元素访问。
  2. 自动转换机制
    • 当元素数量超过zset-max-ziplist-entries(默认128)或元素大小超过zset-max-ziplist-value(默认64字节)时,转换为跳跃表+哈希表结构。
  1. 有序性
    元素按分数(score)从小到大排序,分数可重复,但元素唯一(通过哈希表去重)。
  2. 高效范围操作
    支持按分数或排名(索引)查询范围数据,时间复杂度为O(log N),适合排行榜、时间序列等场景。
  3. 双重访问能力
    • 通过元素值直接访问分数(ZSCORE,O(1))。
    • 通过分数或排名访问元素(如ZRANGE,O(log N + M),M为返回元素数)。
  4. 动态更新与计算
    • 支持分数更新(ZADD覆盖写入),并自动调整排序。
    • 提供集合运算(如ZUNIONSTORE),支持权重与聚合规则(SUM/MIN/MAX)。
# 1. 添加或更新成员及分数(返回成功添加数量)
> `ZADD myzset 95 "Alice" 80 "Bob"`
# 2. 删除指定成员(返回成功删除数量)
> `ZREM myzset "Bob"`
# 3. 获取成员的分数,不存在则返回 `nil`
> `ZSCORE myzset "Alice"`
# 4. 增加成员的分数(返回更新后的分数)
> `ZINCRBY myzset 10 "Alice"`
# 5. 获取成员升序排名(从0开始),不存在则返回 `nil`
> `ZRANK myzset "Alice"`
# 6. 获取成员降序排名(从0开始),不存在则返回 `nil`
> `ZREVRANK myzset "Alice"`
# 7. 按升序排名范围获取成员(支持 `WITHSCORES` 返回分数)
> `ZRANGE myzset 0 2 WITHSCORES` 获取前3名成员及分数
# 8. 按降序排名范围获取成员(支持 `WITHSCORES` 返回分数)
> `ZREVRANGE myzset 0 2 WITHSCORES` 获取前3名成员及分数
# 9. 按分数范围获取成员(支持 `WITHSCORES``LIMIT` 分页)
> `ZRANGEBYSCORE myzset 80 100` 获取分数在 [80, 100] 的成员
# 10. 按分数范围降序获取成员(支持 `WITHSCORES``LIMIT` 分页)
> `ZREVRANGEBYSCORE myzset 100 80` 获取分数在 [80, 100] 的成员(降序)
# 11. 统计分数范围内的成员数量
> `ZCOUNT myzset 80 100` 统计分数在 [80, 100] 的成员数
# 12. 获取集合成员总数
> `ZCARD myzset` 返回集合中所有成员的数量
# 13. 删除并返回分数最高的成员(支持删除多个)
> `ZPOPMAX myzset 1` 删除并返回分数最高的1个成员
# 14. 删除并返回分数最低的成员(支持删除多个)
> `ZPOPMIN myzset 1` 删除并返回分数最低的1个成员
# 15. 计算并存储多个有序集合的并集(支持权重和聚合规则)
> `ZUNIONSTORE result 2 set1 set2 WEIGHTS 2 1 AGGREGATE SUM`
# 16. 计算并存储多个有序集合的交集(支持权重和聚合规则)
> `ZINTERSTORE result 2 set1 set2 WEIGHTS 2 1 AGGREGATE SUM`
  1. 实时排行榜
ZADD game_rank 1500 "PlayerA" 2000 "PlayerB"
ZREVRANGE game_rank 0 9 WITHSCORES # 展示前10名玩家

游戏得分、热帖点击量等动态排序场景。

  1. 延迟队列
ZADD delay_queue <到期时间戳> "任务ID"
ZRANGEBYSCORE delay_queue 0 <当前时间戳> # 获取已到期任务

将任务到期时间作为分数,定时轮询到期任务。

  1. 带权重的优先队列
ZADD tasks 10 "备份DB" 5 "发送邮件"
ZREMRANGEBYRANK tasks 0 0 # 移除并处理优先级最高的任务

按优先级处理任务(分数越高优先级越高)。

  1. 时间轴/动态流
ZADD user:1001:feeds <时间戳> "动态内容"
ZREVRANGE user:1001:feeds 0 9 # 获取最新10条动态

按时间戳存储用户动态,支持分页查询。

  1. 数据统计与过滤
ZADD sales 3000 "订单A" 5000 "订单B"
ZCOUNT sales 2000 6000 # 统计销售额在2000~6000的订单数

统计指定分数区间的用户数量或金额分布。

注意事项

  1. 大范围查询性能
    • ZRANGE/ZREMRANGEBYSCORE等范围操作需谨慎,避免一次返回过多数据(如百万级),建议分页或使用ZSCAN
  2. 内存占用优化
    • 尽量使用整数分数以减少内存占用(触发ziplist编码)。
    • 超大集合可通过分片(如按业务ID哈希分桶)降低单个Sorted Set大小。
  3. 分数相同排序规则
    • 若多个元素分数相同,Redis按字典序排列成员,需业务层处理排序冲突。
  4. 集合运算成本
    • ZUNIONSTORE/ZINTERSTORE等操作复杂度较高,数据量大时建议异步执行。
  5. 合理选择数据结构
    • 若无需排序或分数,优先使用Set或Hash;若需多维度排序,可结合多个Sorted Set。