全部学科
Python全栈
python
NodeJS全栈
nodejs
小程序首页
📅 2026-05-12 8 分钟 ✍️ juanwangdev

Redis有序集合

有序集合(ZSet/Sorted Set)是带分数(score)排序的集合,元素不重复,按分数升序排列,适合排行榜、评分系统等场景。

结构概述

基本特点

Bash
- 不重复字符串集合
- 每个元素关联一个分数(score)
- 按分数升序排列
- 支持范围查询和排名查询
- 单个ZSet最多2^32-1个元素

结构示意

Bash
score(分数) → member(元素)
100 → player1
95  → player2
90  → player3
85  → player4
80  → player5

按分数升序排列,分数可重复,元素不重复

内部编码

ziplist编码

Bash
触发条件:
- 元素数量 ≤ zset-max-ziplist-entries(默认128)
- 所有元素大小 ≤ zset-max-ziplist-value(默认64字节)

特点:
- 紧凑连续内存
- 元素和分数顺序存储
- 内存效率高
- 查找效率较低

skiplist编码

Bash
触发条件:
- 元素数量 > 128
- 或元素大小 > 64字节

特点:
- 跳表 + 哈希表组合
- 跳表:有序结构,支持范围查询
- 哈希表:O(1)查找元素分数
- 查找和范围查询高效

查看编码

Bash
ZADD leaderboard 100 "player1"
OBJECT ENCODING leaderboard
# 返回: "ziplist"

for i in {1..200}; do
    ZADD large:zset $i "player$i"
done
OBJECT ENCODING large:zset
# 返回: "skiplist"

跳表原理

跳表结构

Bash
多层链表结构,概率性分层:
Level 4:     [100]────────────────────→
Level 3:     [100]───────[200]────────→
Level 2: [50][100][150][200][250][300]→
Level 1: [50][100][150][200][250][300]→

从高层快速跳跃,减少比较次数
查找效率O(logN),接近平衡树

跳表优势

Bash
1. 查找高效:O(logN)
2. 插入高效:O(logN)
3. 删除高效:O(logN)
4. 范围查询:O(logN + M)
5. 实现简单:比平衡树简单
6. 内存占用:比平衡树小

Redis跳表实现

Bash
- 最大32层
- 随机决定层数
- 每层概率为25%
- 同时维护哈希表存储分数

应用场景

1. 排行榜

Bash
# 游戏排行榜
ZADD leaderboard 1000 "player1" 950 "player2" 900 "player3"

# 获取前10名(降序)
ZREVRANGE leaderboard 0 9 WITHSCORES

# 获取玩家排名
ZREVRANK leaderboard "player1"

# 增加分数
ZINCRBY leaderboard 50 "player1"

2. 热榜/热搜

Bash
# 热门文章(浏览量为分数)
ZADD hot:articles 1000 "article:500" 800 "article:501"

# 获取热门文章
ZREVRANGE hot:articles 0 10

# 增加热度
ZINCRBY hot:articles 100 "article:500"

3. 延时队列

Bash
# 任务执行时间为分数
ZADD delay:queue 1700000000 "task:1001"

# 获取到期任务
ZRANGEBYSCORE delay:queue 0 {current_timestamp}

# 移除已处理任务
ZREM delay:queue "task:1001"

4. 范围查询

Bash
# 价格范围查询
ZADD products:price 99 "product:A" 199 "product:B" 299 "product:C"

# 查询100-200价格区间商品
ZRANGEBYSCORE products:price 100 200 WITHSCORES

5. 权重队列

text
# 优先级队列(高分数优先)
ZADD priority:queue 10 "task:low" 50 "task:medium" 100 "task:high"

# 获取最高优先级任务
ZREVRANGE priority:queue 0 0

6. 最新列表(时间戳排序)

text
# 消息时间戳为分数
ZADD messages:recent 1700001000 "msg:1" 1700002000 "msg:2"

# 获取最新消息
ZREVRANGE messages:recent 0 10

与Set对比

特性ZSetSet
排序按分数排序无序
分数有score
范围查询支持不支持
排名查询支持不支持
内存占用较大较小
集合运算不支持支持

操作特点

O(1)操作

text
ZSCORE:获取分数
ZCARD:元素数量
ZINCRBY:增加分数

O(logN)操作

text
ZADD:添加元素
ZREM:删除元素
ZRANK/ZREVRANK:获取排名

O(logN + M)操作

text
ZRANGE/ZREVRANGE:范围获取
ZRANGEBYSCORE:分数范围
ZREMRANGEBYSCORE:删除范围
# M为返回/删除元素数量

内存优化

ziplist编码

text
# 调整阈值保持ziplist
zset-max-ziplist-entries 256
zset-max-ziplist-value 128

# 延迟转换,节省内存

分数精度

text
分数为double类型(64位浮点数)
整数分数内存效率更高
避免不必要的浮点分数

性能建议

范围查询优化

text
# 使用LIMIT分页
ZRANGEBYSCORE zset 0 100 LIMIT 0 20

# 减少返回元素数量
# 降低传输和内存开销

大ZSet遍历

text
# 使用ZSCAN分批遍历
ZSCAN leaderboard 0 COUNT 100

批量操作

text
# 批量添加
ZADD zset 1 "a" 2 "b" 3 "c"
# 比多次单独ZADD效率高

注意事项

分数重复

text
分数可以重复
同分数元素按字典序排列
排序稳定性需要注意

元素唯一性

text
# 重复添加更新分数
ZADD zset 100 "a"
ZADD zset 200 "a"
# 元素"a"分数变为200

编码转换

text
ziplist转skiplist不可逆
大ZSet内存占用较大
合理控制元素数量

编码对比

编码条件内存效率查找效率范围效率
ziplist≤128元素且≤64字节O(N)O(N)
skiplist>128元素或>64字节O(logN)O(logN+M)

要点总结

  • 有序集合是带分数排序的不重复集合
  • ziplist编码适合小数据(≤128元素),内存高效
  • skiplist编码适合大数据,跳表+哈希表实现
  • 跳表O(logN)查找、插入、删除,支持高效范围查询
  • 应用场景:排行榜、热搜、延时队列、范围查询、优先级队列
  • ZRANK升序排名,ZREVRANK降序排名(从0开始)
  • ZRANGEBYSCORE按分数范围查询,支持LIMIT分页
  • 大ZSet使用ZSCAN遍历,避免阻塞
  • 调整zset-max-ziplist-entries/value可延迟转换,优化内存

📝 发现内容有误?点击此处直接编辑

← 上一篇 Redis字符串
下一篇 → Redis集合
想查看更多题目和详细解析?
小程序提供完整的题库、模拟考试和详细解析
马上就来

长按或扫描二维码,立即体验

扫码体验小程序
马上就来
使用微信扫描二维码
立即体验完整题库