当前位置: 首页 > ds >正文

redis----zset详解

Redis 的 Zset(Sorted Set,有序集合)是一种兼具唯一性有序性的复合数据结构,在实际开发中常用于排行榜、延时任务、范围统计等场景。

核心特性

  • 元素唯一,分数排序:每个元素(member)唯一,但分数(score)可重复。Zset 会根据分数对元素进行升序排序,分数相同则按元素字典序排序。
  • 动态排序:元素的分数可随时更新,更新后 Zset 会自动重新排序,无需手动维护。
  • 高效性能:基于跳表(Skip List)和哈希表实现,插入、删除、范围查询的时间复杂度均为 O (log N),在大数据量下仍能保持高效。

常用命令

元素操作

  • ZADD:添加或更新元素及分数

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

    • NX:仅当元素不存在时添加
    • XX:仅当元素存在时更新分数
    • INCR:将分数视为增量(如积分累加)
      示例:

    redis

    ZADD rank 95 "Alice" 88 "Bob" 92 "Charlie"  # 批量添加
    ZADD rank XX 98 "Alice"                     # 更新Alice的分数
    ZADD rank INCR 5 "Bob"                      # Bob的分数加5
    
  • ZSCORE:获取元素的分数

    ZSCORE key member
    

    示例:ZSCORE rank "Alice" → 返回 "98"

有序查询

  • ZRANGE:按分数升序查询指定范围元素(0 为第一个,-1 为最后一个)

    ZRANGE key start end [WITHSCORES]
    

    示例:ZRANGE rank 0 -1 WITHSCORES → 返回带分数的元素列表

  • ZREVRANGE:按分数降序查询(适合排行榜 “从高到低”)

    ZREVRANGE key start end [WITHSCORES]
    

    示例:ZREVRANGE rank 0 1 WITHSCORES → 返回 Top 2 元素

范围统计与删除

  • ZRANGEBYSCORE:按分数区间查询元素

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

    示例:ZRANGEBYSCORE rank 90 100 → 查询分数 90-100 的元素

  • ZREM:删除指定元素

    ZREM key member [member ...]
    

    示例:ZREM rank "Bob" → 删除 Bob,返回删除数量

典型应用场景

  1. 排行榜系统:如游戏积分榜、电商销量榜,用 ZREVRANGE 快速获取 Top N,ZSCORE 实时查询用户排名。
  2. 延时任务队列:将任务 ID 作为元素,执行时间戳作为分数,定期用 ZRANGEBYSCORE 获取 “已到执行时间” 的任务。
  3. 范围统计:如统计 “分数 80-90 分的学生”“粉丝数 1 万以上的博主”,通过 ZRANGEBYSCORE 高效筛选。

注意事项

  • 分数精度:分数为 64 位浮点型,避免过度依赖高精度(如小数位数过多可能导致排序误差)。
  • 大数据量优化:若 Zset 元素超百万级,避免使用 ZRANGE 0 -1 全量查询,建议分页查询(如 ZRANGE 0 99)。
  • 内存占用:Zset 比普通 Set 内存占用稍高,若对内存敏感,需结合业务合理使用。

内部编码

Redis 中 Zset 的内部编码并非固定,会根据数据规模自动切换,核心目标是平衡「内存效率」和「操作性能」,主要包含两种编码形式:

一、ziplist(压缩列表)编码

这是 Zset 存储小规模数据时的默认编码,触发条件需同时满足以下 2 个配置阈值(可在 redis.conf 调整):

  • 元素总数量 ≤ zset-max-ziplist-entries(默认值:128)
  • 每个元素的「member(成员)」字符串长度 ≤ zset-max-ziplist-value(默认值:64 字节)

1. 存储结构

ziplist 是连续的内存块,元素按「score(分数)升序」依次存储,格式为:
[zlbytes(总长度)][zltail(尾偏移)][zllen(元素数)][score1][member1][score2][member2]...[zlend(结束标识)]

  • score:以「小端字节序的浮点型」存储(节省空间);
  • member:以原始字符串形式存储,无额外指针开销。

2. 核心特点

  • 优点:内存占用极低(连续内存 + 紧凑存储),遍历效率高(无需跳转指针);
  • 缺点:插入 / 删除元素时需移动后续内存块,时间复杂度为 O (n),数据量大时性能骤降。

二、skiplist(跳表)+ dict(哈希表)编码

当 Zset 数据规模超过 ziplist 的阈值(元素数超 128 或 member 长度超 64 字节)时,Redis 会自动转为该编码,这是 Zset 处理「大规模数据」的核心结构。

1. 结构组成(双结构协同)

两种结构共享同一份数据(通过指针关联,无冗余存储),各自负责不同场景的高效操作:

(1)skiplist(跳表)—— 维护有序性与范围操作
  • 本质:多层级链表结构,每个节点包含多个「层级指针」(类似 “高速公路 + 普通公路” 的分层索引);
  • 作用:按 score 升序存储所有元素,支持 O(log n) 复杂度的插入、删除,以及范围查询(如 ZRANGEZREVRANGEZRANGEBYSCORE 等);
  • 优势:相比平衡二叉树(如红黑树),跳表实现更简单,且范围查询效率更高。
(2)dict(哈希表)—— 快速定位元素分数
  • 本质:经典的键值对结构,「键 = member」,「值 = 对应的 score」;
  • 作用:支持 O(1) 复杂度的「根据 member 查 score」操作(如 ZSCORE 命令);
  • 优势:避开跳表的 O (log n) 查找开销,直接通过哈希映射快速定位。

三、编码转换规则

  • 单向转换:仅支持「ziplist → skiplist+dict」,一旦触发转换,后续即使删除元素使数据规模缩小,也不会再转回 ziplist;
  • 触发时机:添加元素时实时检查阈值,一旦超过立即转换(无需手动干预);
  • 配置调整:若业务中 Zset 多为小规模数据,可适当调大 zset-max-ziplist-entries 或 zset-max-ziplist-value,进一步节省内存;若多为大规模数据,可调小阈值,提前切换到高性能编码。

四、查看当前编码

通过 OBJECT ENCODING 命令可直接查看某个 Zset 的内部编码,示例:

127.0.0.1:6379> ZADD myzset 1 "a" 2 "b"  # 小规模数据,用 ziplist
(integer) 2
127.0.0.1:6379> OBJECT ENCODING myzset
"ziplist"  # 输出 ziplist127.0.0.1:6379> ZADD myzset 3 "long-long-member-more-than-64-bytes-xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
(integer) 1
127.0.0.1:6379> OBJECT ENCODING myzset
"zset"  # 输出 zset,代表 skiplist+dict 编码

http://www.xdnf.cn/news/19591.html

相关文章:

  • Langflow Memory 技术深度分析
  • Langflow RAG 技术深度分析
  • 人工智能学习:机器学习相关面试题(二)
  • MySQL-视图与用户管理
  • Langchain指南-关键特性:如何流式传输可运行项
  • 如何解决pip安装报错ModuleNotFoundError: No module named ‘SQLModel’问题
  • 案例——从零开始搭建 ASP.NET Core 健康检查实例
  • 齿轮加工刀具材料漫谈:从高速钢到陶瓷的 “切削艺术”
  • 传统数据库out啦!KINGBASE ES V9R1C10 开启国产数据库“修仙”新纪元!
  • Day19_【机器学习—线性回归 (2)】
  • 正则表达式 Python re 库完整教程
  • 生存分析入门教程
  • 馈电油耗讲解
  • AssemblyLoadContext`的插件化架构
  • Qt libcurl的下载、配置及简单测试 (windows环境)
  • springboot项目启动时打印maven打包时间
  • [Mysql数据库] 知识点总结8
  • 计算机网络:(十六)TCP 的运输连接管理
  • Ring Buffer解析
  • 仓颉语言Web框架中的路由分组
  • linux系统学习(6.软件包管理)
  • 十分钟快速掌握 YML YAML 文件
  • 07.《交换机三层功能、单臂路由与端口安全基础知识》
  • 在Linux环境安装Maven(保姆级别)
  • leetcode 面试题 01.01.判定字符是否唯一
  • 【高级】系统架构师 | 信息系统基础
  • 基于Seurat的空转单样本数据分析流程学习(一)
  • JavaScript中的XMLHttpRequest对象分析
  • 基于单片机智能保温杯/智能水杯
  • Java基础第7天总结(代码块、内部类、函数式编程)