Redis数据结构对象之集合对象和有序集合对象

news2024/9/22 21:28:54

集合对象

集合对象的编码可以是intset或者hashtable.

概述

intset编码的集合对象使用整数集合作为底层实现,集合对象包含的所有元素都被保存在整数集合里面。

另一方面,hashtable编码的集合对象使用字典作为底层实现,字典的每个键都是一个字符串对象,每个字符串对象包含了一个集合对象,而字典的值则全部被设置为NULL.

例子

  • 举个例子。以下代码创建一个如图所示的intset编码集合对象
127.0.0.1:6379> SADD numbers 1 3 5
(integer) 3

在这里插入图片描述

  • 举个例子,以下代码创建一个如图所示的hashtable编码集合对象
127.0.0.1:6379> SADD fruits "apple" "banana" "cherry"
(integer) 3

在这里插入图片描述

编码的转换。

当集合对象可以同时满足以下两个条件时,对象使用intset编码:

  • 1.集合对象保存的所有元素都是整数值
  • 2.集合对象保存的元素不超过512个
    不能满足中两个条件的集合对象需要使用hashtable编码

对于使用intset编码的集合对象来说,当使用intset编码所需的两个条件的任意一个不能被满足时,就会执行对象的编码转换操作,原本保存在整数集合中的所有元素都会被转移并保存到字典里面,并且对象的编码也会从intset变为hashtable

注意:

第二个条件的上限值是可以修改的,具体请看配置文件中关于set-max-intset-entries选项的说明

例子

  • 举个例子,以下代码创建了一个只包含整数的集合对象,该对象的编码为intset:
127.0.0.1:6379> SADD numbers 1 3 5
(integer) 3

不过,只要我们向这个只包含整数元素的集合对象添加一个字符串元素,集合对象的编码转移操作就会被执行:

127.0.0.1:6379> SADD numbers "seven"
(integer) 1
127.0.0.1:6379> OBJECT ENCODING numbers
"hashtable"

除此之外,如果我们创建一个包含512个整数元素的集合对象,那么对象的编码应该会是intset:

127.0.0.1:6379> EVAL "for i=1, 512 do redis.call('SADD', KEYS[1], i) end" 1 integers
(nil)
127.0.0.1:6379> SCARD integers
(integer) 512

但是我们再向集合添加一个新的元素,使得整个元素的元素数量变成513,那么对象的编码转换操作就会被执行:

127.0.0.1:6379> SADD integers 513
(integer) 1
127.0.0.1:6379> OBJECT ENCODING integers
"hashtable"

有序集合对象

有序集合的编码可以是ziplist或者skiplist。

概述

ziplist

ziplist编码的有序集合对象使用压缩列表作为底层实现,每个集合元素使用两个紧挨在一起的压缩列表节点来保存,第一个节点保存元素的成员(member),而第二个元素则保存元素的分值(score).压缩列表
内的集合元素按分值从小到大进行排序,分值较小的元素被放置在表头的位置(相对分值节点来说),而分值较大的元素则被放置在靠近表尾的位置。

例子
  • 举个例子,如果执行以下ZADD命令,那么服务器将创建一个有序集合作为price键的值:
127.0.0.1:6379> ZADD price 8.5 apple 50 banana 6.0 cherry
(integer) 3

如果price键的值对象使用的是ziplist编码,那么这个值对象将会是如图所示的样子,对象使用的压缩列表则会是如图所示的样子
在这里插入图片描述
在这里插入图片描述

skiplist

skiplist编码的有序集合对象使用zset结构作为底层实现,,一个zset结构同时包含一个字典和一个跳跃表

typedef struct zset{
 zskiplist *zsl;
 dict * dict;
}zset

zset结构中的zsl跳跃表按分值从小到大保存了所有集合元素,每个跳跃表节点都保存了一个集合元素:
跳跃表节点的object属性保存了元素的成员,而跳跃表节点的score属性则保存了元素的分值。通过这个跳跃表,程序可以对有序集合进行范围型操作,比如ZRANK,ZRANGE等命令就是基于跳跃表API来实现的

除此之外,zset结构中的dict字典为有序集合创建了一个从成员到分值的映射,字典中的每个键值对都保存了一个集合元素:字典的键保存了元素的成员,而字典的值则保存了元素的分值。通过这个字典,程序可以用O(1)
复杂度查找给定成员的分值,ZSCORE命令就是根据这一特性实现的,而很多其他有序集合命令都在实现的内部用到了这一特性。
有序集合每个元素都是一个字符串对象,而每个元素的分值都是一个double类型的浮点数。值得一提的是,虽然zset结构同时使用跳跃表和字典来保存有序集合的元素,但这两种数据结构都会通过指针来共享相同的成员和分值,所以同时使用跳跃表和字典来保存集合元素不会产生任何重复成员或分值,也不会因此而浪费额外的内存

为什么有序集合需要同时使用跳跃表和字典来实现?

在理论上,有序集合可以单独使用字典或者跳跃表的其中一种数据结构来实现,但无论单独使用字典还是跳跃表,在性能上对比起同时使用字典和跳跃表都会有所降低。

  • 举个例子,如果只是用字典来实现有序集合,虽然以O(1)的复杂度查找成员的分值这一特性会被保留,但是字典以无须的方式来保存集合元素,所以每次在执行范围型操作——比如ZRANK,ZRANGE等命令时,程序都需要对字典保存的所有元素进行排序,完成这种排序需要至少O(NlogN)时间复杂度,以及额外的O(N)内存空间(因为要创建一个数组来保存排序后的元素)。另一方面,如果只使用跳跃表来实现有序集合,那么跳跃表执行范围型操作的所有优点都会被保留,但因为没有了字典,所以根据成员查找分值这一操作的复杂度将从O(1)上升为O(logN)。因为以上原因,为了让有序集合的查找范围和范围型操作都尽可能快地执行,Redis选择了同时使用字典和跳跃表两种数据结构来实现有序集合
例子

举个例子,如果前面price键创建的不是ziplist编码的有序集合对象,而是skiplist编码的有序集合对象,那么这个有序集合对象将会如图所示,而对象所使用的zset结构也将如图所示
在这里插入图片描述
在这里插入图片描述

注意:

为了展示方便,在字典和跳跃表中重复展示了各个元素的成员和分值,但在实际中,字典和跳跃表会共享元素的成员和分值,所以并不会造成任何数据重复,也不会因此而浪费任何内存。

编码的转换

当有序集合对象可以同时满足以下两个条件时,对象使用ziplist编码

  • 1.有序集合保存的元素数量小于128个
  • 2.有序集合保存的所有元素成员的长度都小于64字节
    不能满足以上两个条件的有序集合对象将使用skiplist编码

对于使用ziplist编码的有序集合对象来说,当使用ziplist比那吗所需的两个条件中的任意一个不能被满足时,程序就会执行编码转换操作,将原本储存在压缩列表里面的所有集合元素转移到zset里面,并将对象的编码从ziplist改为skiplist

例子

  • 举个例子,以下代码展示了有序集合因为包含了过多元素而引发编码转换的情况:
// 对象包含了128个元素
127.0.0.1:6379> EVAL "for i=1, 128 do redis.call('ZADD', KEYS[1],i,i) end" 1 numbers
(nil)
127.0.0.1:6379> ZCARD numbers
(integer) 128
127.0.0.1:6379> OBJECT ENCODING numbers
"ziplist"
// 再添加一个新元素
127.0.0.1:6379> ZADD numbers 3.14 pi
(integer) 1
// 对象数量变为129个
127.0.0.1:6379> ZCARD numbers
(integer) 129
// 编码已改变
127.0.0.1:6379> OBJECT ENCODING numbers
"skiplist"
  • 以下代码则展示了有序集合对象因为元素的成员过长而引起编码转换的情况
// 向有序集合添加一个成员只有三字节长的元素
127.0.0.1:6379> ZADD blah 1.0 www
(integer) 1
127.0.0.1:6379> OBJECT ENCODING blah
"ziplist"
// 向有序集合添加一个成员为66字节长的元素
ZADD blah 2.0 ooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooo
// 编码已改变
127.0.0.1:6379> OBJECT ENCODING blah
"skiplist"

注意:

以上两个条件的上限值是可以修改的,具体请看配置文件中关于zset-max-ziplist-entries和zset-max-ziplist-value选项的说明

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1527241.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

REDHAWK——连接(续)

文章目录 前言一、突发 IO1、数据传输①、输入②、输出 2、突发信号相关信息 (SRI)3、多输出端口4、使用复数数据①、在 C 中转换复数数据 5、时间戳6、端口统计①、C 二、消息传递1、消息生产者①、创建一个消息生产者②、发送消息 2、消息消费者①、创建消息消费者②、注册接…

力扣106---从中序和后序序列构造二叉树

题目描述: 给定两个整数数组 inorder 和 postorder ,其中 inorder 是二叉树的中序遍历, postorder 是同一棵树的后序遍历,请你构造并返回这颗 二叉树 。 示例 1: 输入:inorder [9,3,15,20,7], postorder [9,15,7,20…

项目性能优化—使用JMeter压测SpringBoot项目

我们的压力测试架构图如下: 配置JMeter 在JMeter的bin目录,双击jmeter.bat 新建一个测试计划,并右键添加线程组: 进行配置 一共会发生4万次请求。 ctrl s保存; 添加http请求: 配置http请求:…

工控机的无限可能2--智慧城市

一、智能柜 随着网络技术的发展,网购因方便快捷、价格优惠、不受时空限制等优势已成为用户重要的消费方式。快递员因满柜,或柜型单一不能投递,只能将快件堆放在车上或公共过道处苦等,快递、资产管理也随之出现。 如下&#xff0…

使用Windows远程访问Kali Linux桌面

安装xrdp、xfce4 apt-get install -y xrdp xfce4修改 xrdp 配置文件启用 xfce 桌面 vim /etc/xrdp/startwm.sh修改后文件如下: #!/bin/sh # xrdp X session start script (c) 2015, 2017, 2021 mirabilos # published under The MirOS Licence# Rely on /etc/pam…

Unity InputField实现框自适应内容简便方法

要实现InputField框自适应输入内容,除了通过代码进行处理,还可以是使用以下简便的方法。 1、创建InputField组件:右键->UI->Input Field -TextMeshPro。 2、把Input Field Settings中的Line Type设置为Multi Line Newline模式&#x…

第五篇:数字视频广告格式概述 - IAB视频广告标准《数字视频和有线电视广告格式指南》

第五篇:第五篇:数字视频广告格式概述 - IAB视频广告标准《数字视频和有线电视广告格式指南 --- 我为什么要翻译介绍美国人工智能科技公司IAB系列技术标准(2) ​​​​​​​翻译计划 第一篇序言第二篇简介和目录第三篇概述- IA…

ubuntu下在vscode中配置matplotlibcpp

ubuntu下在vscode中配置matplotlibcpp 系统:ubuntu IDE:vscode 库:matplotlib-cpp matplotlibcpp.h文件可以此网址下载:https://github.com/lava/matplotlib-cpp 下载的压缩包中有该头文件,以及若干实例程序。 参考…

钡铼R40工业路由器在果园智能化生产管理系统中的重要角色

在现代果园智能化生产管理系统中,钡铼R40工业路由器扮演着至关重要的角色。它作为物联网技术的核心组件,将果园的智能化管理推向了一个全新的高度,实现了对果园环境、果树生长状况以及各类生产设备的实时监控与精准调控。 首先,钡…

Apache Dolphinscheduler - 无需重启 Master-Server 停止疯狂刷日志解决方案

记录的是一个 3.0 比较难搞的问题,相信不少使用过 3.0 的用户都遇到过 Master 服务中存在一些工作流或者任务流一直不停的死循环的问题,导致疯狂刷日志。不过本人到现在也没找到最关键的触发原因,只是看到一些连锁反应带来的结果…… 影响因素…

内网穿透的应用-如何使用Docker安装DockerUI可视化管理工具无公网IP远程访问

文章目录 前言1. 安装部署DockerUI2. 安装cpolar内网穿透3. 配置DockerUI公网访问地址4. 公网远程访问DockerUI5. 固定DockerUI公网地址 前言 DockerUI是一个docker容器镜像的可视化图形化管理工具。DockerUI可以用来轻松构建、管理和维护docker环境。它是完全开源且免费的。基…

glib交叉编译

Glib交叉编译 逸一时,误一世。 —— 田所浩二「夏夜银梦」 交叉编译 GLib 涉及到在一个平台上生成能够在另一个平台上运行的目标文件。在这种情况下,我们将会在一台主机(通常是开发机器)上使用交叉编译工具链来构建 GLib 库&#…

RabbitMQ在Java中使用 SpringBoot 从基础到高级

充分利用每一个监听者 需要充分利用每一个消费者,需要在配置文件中加上prefetch配置并设置为1 rabbitmq:listener:simple:prefetch: 1 # 每次只能获取一条消息,处理完成才能获取下一个消息创建交换机和队列 创建队列 "fanout.queue1"&…

RK3588_Qt交叉编译环境搭建

buildroot编译 进入 /home/linux/plat/rk3588/sdk/buildroot 目录下,执行 Source ./envsetup.sh 选择具体平台编译,后再执行make编译 /home/linux/plat/rk3588/sdk/buildroot/output/OK3568/images 生成的rootfs.ext2镜像重新烧写到rk3568开发板中&…

计算地球圆盘负荷产生的位移

1.研究背景 计算受表面载荷影响的弹性体变形问题有着悠久的历史,涉及到许多著名的数学家和物理学家(Boussinesq 1885;Lamb 1901;Love 1911,1929;Shida 1912;Terazawa 1916;Munk &…

22款Visual Studio Code实用插件推荐

前言 Visual Studio Code是一个轻量级但功能强大的源代码编辑器,轻量级指的是下载下来的Visual Studio Code其实就是一个简单的编辑器,强大指的是支持多种语言的环境插件拓展,也正是因为这种支持插件式安装环境开发让Visual Studio Code成为…

计算机二级C语言的注意事项及相应真题-5-程序设计

目录 41.计算下列级数和,和值由函数值返回42.统计出x所指数组中能被e整除的所有元素,这些元素的和通过函数值返回主函数,元素个数通过形参num返回主函数43.使数组右上三角元素中的值乘以m44.将a、b中的两个两位正整数合并形成一个新的整数放在…

3.18数据结构

一、数据结构----->用来组织存储数据 一组用来保存一种或多种特定关系的数据的集合(组织和存储数据) 程序 数据结构 算法 MVC:软件设计架构 M:数据的管理(数据结构) V:视图&#xff0c…

SQLiteC/C++接口详细介绍之sqlite3类(十八)

返回目录:SQLite—免费开源数据库系列文章目录 上一篇:SQLiteC/C接口详细介绍之sqlite3类(十七) 下一篇:SQLiteC/C接口详细介绍sqlite3_stmt类(一) ​ 56.sqlite3_update_hook 函数功能&am…

【边缘智能】Jetson板卡上安装QT5与OpenCV集成

学习《OpenCV应用开发:入门、进阶与工程化实践》一书 做真正的OpenCV开发者,从入门到入职,一步到位! 安装QT5与QT Creator 如果只是简单的使用QT的GUI库,没有其它要求,其实特别容易,一行命令行…