Redis 中 Sorted Set(有序集合)类型
Redis的Sorted Set是一种有序且元素唯一的数据结构,每个元素关联一个分数(score),实现按分数排序和高效范围查询。
- 底层实现
- ziplist(压缩列表):元素较少时,使用连续内存存储(元素和分数交替排列),节省内存。
- 跳跃表(skiplist) + 哈希表:默认实现方式,跳跃表支持快速范围操作,哈希表保证元素唯一性并实现O(1)复杂度元素访问。
- 自动转换机制
- 当元素数量超过
zset-max-ziplist-entries(默认128)或元素大小超过zset-max-ziplist-value(默认64字节)时,转换为跳跃表+哈希表结构。
- 当元素数量超过
- 有序性
元素按分数(score)从小到大排序,分数可重复,但元素唯一(通过哈希表去重)。 - 高效范围操作
支持按分数或排名(索引)查询范围数据,时间复杂度为O(log N),适合排行榜、时间序列等场景。 - 双重访问能力
- 通过元素值直接访问分数(
ZSCORE,O(1))。 - 通过分数或排名访问元素(如
ZRANGE,O(log N + M),M为返回元素数)。
- 通过元素值直接访问分数(
- 动态更新与计算
- 支持分数更新(
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`- 实时排行榜
ZADD game_rank 1500 "PlayerA" 2000 "PlayerB"ZREVRANGE game_rank 0 9 WITHSCORES # 展示前10名玩家游戏得分、热帖点击量等动态排序场景。
- 延迟队列
ZADD delay_queue <到期时间戳> "任务ID"ZRANGEBYSCORE delay_queue 0 <当前时间戳> # 获取已到期任务将任务到期时间作为分数,定时轮询到期任务。
- 带权重的优先队列
ZADD tasks 10 "备份DB" 5 "发送邮件"ZREMRANGEBYRANK tasks 0 0 # 移除并处理优先级最高的任务按优先级处理任务(分数越高优先级越高)。
- 时间轴/动态流
ZADD user:1001:feeds <时间戳> "动态内容"ZREVRANGE user:1001:feeds 0 9 # 获取最新10条动态按时间戳存储用户动态,支持分页查询。
- 数据统计与过滤
ZADD sales 3000 "订单A" 5000 "订单B"ZCOUNT sales 2000 6000 # 统计销售额在2000~6000的订单数统计指定分数区间的用户数量或金额分布。
注意事项
- 大范围查询性能
ZRANGE/ZREMRANGEBYSCORE等范围操作需谨慎,避免一次返回过多数据(如百万级),建议分页或使用ZSCAN。
- 内存占用优化
- 尽量使用整数分数以减少内存占用(触发ziplist编码)。
- 超大集合可通过分片(如按业务ID哈希分桶)降低单个Sorted Set大小。
- 分数相同排序规则
- 若多个元素分数相同,Redis按字典序排列成员,需业务层处理排序冲突。
- 集合运算成本
ZUNIONSTORE/ZINTERSTORE等操作复杂度较高,数据量大时建议异步执行。
- 合理选择数据结构
- 若无需排序或分数,优先使用Set或Hash;若需多维度排序,可结合多个Sorted Set。