Redis 有序集合 Sorted Set
ZSet 在 Set「成员唯一」的基础上给每个成员挂一个分数(score),集合按分数升序排列,可随时按排名区间取值。排行榜、限时活动积分榜都靠它,是面试与实战的高频类型。
添加成员
ZADD 带分数添加成员,成员已存在则只更新分数,返回新增个数:
ZADD leaderboard 100 user1 90 user2 88 user3
# 输出:(integer) 3
ZADD leaderboard 95 user2 # user2 分数更新为 95
# 输出:(integer) 0
分数可以是整数或小数(如 9.5),同一集合内分数允许并列。
按排名取成员
ZRANGE 按分数升序取区间,配 REV 变降序,WITHSCORES 带分数:
ZRANGE leaderboard 0 -1
# 输出:1) "user3" 2) "user2" 3) "user1"
ZRANGE leaderboard 0 -1 WITHSCORES
# 输出:1) "user3" 2) "88" 3) "user2" 4) "95" 5) "user1" 6) "100"
ZRANGE leaderboard 0 1 REV WITHSCORES # 降序取前两名
# 输出:1) "user1" 2) "100" 3) "user2" 4) "95"
排行榜「取 Top10」就是 ZRANGE key 0 9 REV WITHSCORES 一条命令的事。
查询分数与排名
ZSCORE 看分数,ZRANK 看升序名次(从 0 开始):
ZSCORE leaderboard user1
# 输出:"100"
ZRANK leaderboard user1
# 输出:(integer) 2 # 升序第 3 名
ZRANK leaderboard user3
# 输出:(integer) 0
降序名次可用 ZRANGE ... REV 换算,或直接看集合大小推算。
更新与删除
ZINCRBY 给分数加增量(写积分流水最常用),ZREM 删除成员:
ZINCRBY leaderboard 10 user1
# 输出:"110" # 完成一单任务加 10 分
ZREM leaderboard user3
# 输出:(integer) 1
ZCARD leaderboard
# 输出:(integer) 2 # 成员总数
ZINCRBY 是原子操作,多人并发加分不会丢更新。
常用命令一览
| 命令 | 作用 |
|---|---|
| ZADD | 添加 / 更新成员分数 |
| ZRANGE | 按名次区间取值,REV 降序 |
| ZSCORE / ZRANK | 查分数 / 查名次 |
| ZINCRBY | 分数原子增减 |
| ZREM | 删除成员 |
| ZCARD | 成员总数 |
| ZCOUNT | 分数在区间内的成员数 |
| ZREMRANGEBYSCORE | 按分数区间批量删除 |
典型场景
积分排行榜:每次用户得分 ZINCRBY 更新,展示时降序取前 N:
ZINCRBY game:rank 5 player_88
ZINCRBY game:rank 8 player_12
ZRANGE game:rank 0 9 REV WITHSCORES
延迟/定时任务:把执行时间戳当分数,轮询取「已到期」任务即可(到期后成员删除或另存状态)。
易踩坑
- 分数并列时按成员名做字典序排序,两个并列第 1 实际还有个先后;
- 元素很少时 ZSet 用紧凑编码存储,量大后自动转跳表,无需手动干预;
- 排行榜要「先到先得」,可用 时间戳修正分数(如 分数 = 业务分×大数 - 秒级时间戳)避免并列抖动,量级设计要防溢出。
小结
ZSet 的价值 = Set 唯一性 + 可排序分数。ZADD/ZINCRBY 维护分数,ZRANGE ... REV WITHSCORES 出排行榜,ZSCORE/ZRANK 支持名次查询。记住分数并列的字典序规则,排行榜功能就稳了。