【Redis-03】Redis数据结构与对象原理 -下篇

 承接上篇【Redis-02】Redis数据结构与对象原理 -上篇

8. type-字符串string

在这里插入图片描述

8.1 字符串的三种encoding编码(int + embstr + raw)

  • 如果保存的是整型,并且可以用long类型标识(-9223372036854775808到9223372036854775807),encoding取值为 int
  • 如果是浮点数 + 整型(long类型无法表达) + 字符串,且长度 ≤ 44个字节,encoding 取值为 embstr
  • 如果是浮点数 + 整型(long类型无法表达) + 字符串,且长度 > 44个字节,encoding 取值为 raw
    想知道为什么是44个字节吗?点击这里可以查看https://blog.csdn.net/u013099854/article/details/115399466
    在这里插入图片描述
    在这里插入图片描述

8.1.2 embstr 和 raw两种编码

 这两种编码内部封装的都是sds,站在使用者的角度而言,没什么区别;在底层内存分配及部分操作时,还是有一些不同的,主要体现在以下几点:

  1. embstr是用于保存短字符串的优化编码方式,且embstr编码的字符串对象是只读的,对此编码进行任何的写操作,都会导致字符串变为raw的编码方式;raw是用于保存长字符串的编码方式。
  2. embstr在内存分配和内存释放的时候,只需调用一次对应的函数;而raw需要调用两次内存分配和释放的函数来完成对应的过程;
  3. embstr编码的字符串对象所有的数据都是保存在一块连续的内存里,而raw不一定。

 embstr内存连续,如下图:
在这里插入图片描述
 raw内存不连续,如下图:
在这里插入图片描述

8.1.3 编码转换

  • 整数型经过某些操作,比如append、setrange; encoding: int -> raw
  • 整数型涉及到浮点数的操作,比如incrbyfloat; encoding:int -> embstr或raw
  • 短字符串经过某些写的操作,比如append、setrange; encoding : embstr -> raw
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述

9 type-集合set

在这里插入图片描述
 redis中,set的类型是借助于intset和dict来实现的,与其他结构一样,在某些条件下,set的编码类型会发生变化。我们来看下,set在哪些情况下使用intset,哪些情况下使用dict。

9.1 类型转换

  • 我们创建一个set,写入 1、 3、 5、 7 这样的整数值时,set的encoding是intset,但是如果我们写入非整数 a,就会变成 dict 类型。
  • 我们创建一个set,写入 1、 3、 5、 7 这样的整数值时,set的encoding是intset,但是如果我们写入的整数 >264-1,就会变成 dict 类型。
  • 当set的元素超过 512 个时,编码类型会从 intset转为 dict,这个值也是在redis.conf的配置文件中定义的。
    在这里插入图片描述
     看下面的几个例子:
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述

9.2 两种类型比较

 我们看下set在不同编码下的数据结构,下图分别是intset 和 dict的实现:
在这里插入图片描述
在这里插入图片描述
 在set较小的时候,使用intset可以节省内存,因为dict要维护两个哈希表,链表指针及其他大量元数据,而intset是一整块连续的内存。但是dict的平均查找效率是高于intset的,dict可以支持O(1)的时间复杂度,而intset是有序的整数集合,可以做二分查找,时间复杂度是O(log n)。

 这里需要说明一点的是,如果set使用dict作为底层实现,key是set的元素值,而 value = null。

10 type-哈希hash

在这里插入图片描述
 hash是我们在redis中存储对象比较理想的数据结构,每个对象的属性正好可以对应hash的每个field。hash的底层数据结构就是基于压缩列表和字典这两种类型实现的。

10.1 encoding的编码转换

 当hash对象可以同时满足下面2个条件时,使用的是ziplist,否则就是dict。

  • 哈希对象保存的所有键值对的键和值字符串长度都 ≤ 64个字节;
  • 哈希对象保存的键值对的数量 ≤ 512个;
    在这里插入图片描述

10.2 举例说明

  • 下面这个案例,aa是64个字节,bb是65个字节

在这里插入图片描述

  • 下面这个案例,numbers1是512个键值对,numbers2是513个键值对
    在这里插入图片描述

11 type-有序列表 sorted set

在这里插入图片描述

  Redis中的sorted set,其实是在ziplist,skiplist和dict的基础上共同构建而来的,在不同的场景下,使用的数据结构是不一样的。决定使用哪种数据结构,涉及到redis.conf中的两个配置参数,分别是 zset-max-ziplist-entries 和 zset-max-ziplist-value。

在这里插入图片描述

  • 如果有序集合中的元素数量≤128(对应的ziplist中entry的个数就是128*2=256个),并且所有元素的长度都≤64个字节的时候,就会使用ziplist作为底层的结构实现。
  • 如果有序集合中的元素数量超过128个,或者某个元素成员对象的长度超过64个字节的时候,就会使用zset的数据结构,而zset的数据结构其实就是由1个dict + 1个 zskiplist结构组成的。

在这里插入图片描述
在这里插入图片描述

11.1 使用 ziplist 的数据结构

 前面我们了解的ziplist是占用了一大块连续的内存,它的数据项都是相邻的。在数据项较少的时候,我们向有序集合中插入一条数据,ziplist上面就会插入两个entry节点,成员对象ele在前,分数score在后面,而且这些元素都是按照分值从小到大进行排序保存的。它的优势就是节省内存开销,支持从前往后或者从后往前的顺序查找。

 如果我们执行了这样一条命令,向学生有序集合中插入分数和姓名,他的类型就是ziplist:

在这里插入图片描述

 那么数据结构就是这样的
在这里插入图片描述

11.2 使用 dict + zskiplist 的数据结构

 在数据量比较多的时候,有序集合使用了 dict + zskiplist两种结构共同来实现。dict用于保存数据与分值之间的对应关系,key=成员对象,value=分值,这也是为什么数据值如果相同,后者会覆盖前者的原因。 而zskiplist用于使用分数来查找数据,也支持范围内的查找。虽然zset同时使用了字段和跳跃表,但是这两种数据结构都会通过指针来共享相同的元素和分值,所以不会产生重复的数据,也不会额外占用内存。

 如果我们执行了这样一条命令,向学生有序集合中插入分数和姓名,他的类型就是skiplist(zset):
在这里插入图片描述

11.3 编码的转换

 我现在分别写入128个元素和129个元素、长度为64和长度为65的元素,看一下他们的encoding的编码类型是什么。

在这里插入图片描述

在这里插入图片描述

 可以看到,上面两种情况的encoding编码值确实发生了变化。

 理论上,有序集合可以单独使用dict或者zskiplist来实现,但是为什么要使用两者结合呢,是因为无论单独使用哪一种,在性能上对比起同时使用两者时性能都会有所下降。下面我们看个例子:

在这里插入图片描述

 如果仅使用zskiplist,现在查找dd的排序:首先我们现在知道的是成员对象,而不是分值,所以就没有办法在O(log n)的时间复杂度下找到对应的节点,只能循环遍历,从头开始找,每循环一个对比一下 ele ?= dd,直到命中为止,时间复杂度就是O(n);

 而现在zset借助了dict,首先根据key=dd找到对应的value,这一步在哈希值冲突较小的前提下时间复杂度是O(1),而找到分值score后,借助于zskiplist的特性在O(log n)的时间复杂度下找到dd这个节点,然后再把沿途的跨度数值加起来,就是dd的排位。

在这里插入图片描述

12 type-列表list

在这里插入图片描述

12.1 编码类型

 redis中列表list就是借助于quicklist来实现的,而且只有这一种编码类型。
在这里插入图片描述

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

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

相关文章

IO进程线程 day1 IO基础+标准IO

1、使用fgets统计一个文件的行号 #include <stdio.h> #include<string.h> #include<stdlib.h> int main(int argc, const char *argv[]) {FILE *fpNULL;if((fpfopen("1.c","r"))NULL){return -1;}int count0;char buf;while(buf!EOF){b…

C++多态性——(1)初识多态

归纳编程学习的感悟&#xff0c; 记录奋斗路上的点滴&#xff0c; 希望能帮到一样刻苦的你&#xff01; 如有不足欢迎指正&#xff01; 共同学习交流&#xff01; &#x1f30e;欢迎各位→点赞 &#x1f44d; 收藏⭐ 留言​&#x1f4dd; 苦难和幸福一样&#xff0c;都是生命盛…

modelsim安装使用

目录 modelsim 简介 modelsim 简介 ModelSim 是三大仿真器公司之一mentor的产品&#xff0c;他可以模拟行为、RTL 和门级代码 - 通过独立于平台的编译提高设计质量和调试效率。单内核模拟器技术可在一种设计中透明地混合 VHDL 和 Verilog&#xff0c;常用在fpga 的仿真中。 #…

PAT乙级1045 快速排序

著名的快速排序算法里有一个经典的划分过程&#xff1a;我们通常采用某种方法取一个元素作为主元&#xff0c;通过交换&#xff0c;把比主元小的元素放到它的左边&#xff0c;比主元大的元素放到它的右边。 给定划分后的 N 个互不相同的正整数的排列&#xff0c;请问有多少个元…

中科亿海微UART协议

引言 在现代数字系统设计中&#xff0c;通信是一个至关重要的方面。而UART&#xff08;通用异步接收器/发送器&#xff09;协议作为一种常见的串行通信协议&#xff0c;被广泛应用于各种数字系统中。FPGA&#xff08;现场可编程门阵列&#xff09;作为一种灵活可编程的硬件平台…

个体诊所软件方案,农村医疗服务站社区门诊电子处方管理系统软件教程

个体诊所软件方案&#xff0c;农村医疗服务站社区门诊电子处方管理系统软件教程 一、软件程序问答 1、处方单软件有病历汇总吗 如下图&#xff0c;软件以 佳易王电子处方软件V17.2版本为例说明 点击 病历汇总统计 按钮&#xff0c; 可以按明细查询或病历汇总查询&#xf…

基于JavaWeb实验室预约管理系统(源码+数据库+文档)

一、项目简介 本项目是一套基于JavaWeb实验室预约管理系统&#xff0c;主要针对计算机相关专业的正在做毕设的学生与需要项目实战练习的Java学习者。 包含&#xff1a;项目源码、数据库脚本等&#xff0c;该项目附带全部源码可作为毕设使用。 项目都经过严格调试&#xff0c;e…

rime中州韵 help lua Translator

lua 是 Rime中州韵/小狼毫输入法强大的武器&#xff0c;掌握如何在Rime中州韵/小狼毫中使用lua&#xff0c;你将体验到什么叫 随心所欲。 先看效果 在 rime中州韵 输入效果一览 中的 &#x1f447; help效果 一节中&#xff0c; 我们看到了在Rime中州韵/小狼毫输入法中输入 h…

cpu优化方法

如何看谁拉高了cpu&#xff1f; cpu高的时候有没有抓到进程threadtop&#xff0c;从threadtop找到top 3线程和正常场景对比一下就知道是否有异常对明显有异常的线程&#xff0c;看下是否抓到simplerperf trace或systrace&#xff0c;从trace中找到高频调用栈是否异常如果没有…

常见位运算模板方法总结(包含五道例题)

哈喽大家好&#xff0c;今天博主给大家带来算法基础常见位运算的模板&#xff0c;可以说大家遇到的百分之九十与位运算有关的题都可以用得上。话不多上我们上干货&#xff1a; 一.基础位运算符 << 左移运算符 >> 右移运算符 ~ 取反 & 与运算 | …

【Linux--多线程同步与互斥】

目录 一、线程互斥1.1相关概念介绍1.2互斥量mutex1.3互斥量接口1.3.1初始化互斥量1.3.2销毁互斥量1.3.3互斥量加锁1.3.4互斥量解锁1.3.5使用互斥量解决上面分苹果问题 1.4互斥原理 二、可重入与线程安全2.1相关概念2.2常见线程不安全的情况2.3常见不可重入的情况2.4 可重入与线…

PiflowX组件-JDBCWrite

JDBCWrite组件 组件说明 使用JDBC驱动向任意类型的关系型数据库写入数据。 计算引擎 flink 有界性 Sink: Batch Sink: Streaming Append & Upsert Mode 组件分组 Jdbc 端口 Inport&#xff1a;默认端口 outport&#xff1a;默认端口 组件属性 名称展示名称默…

获奖、买房、出课、维权、购车,我的2023年度总结。

时光如水&#xff0c;岁月如梭。一个典型的小学语文作文的开头。 但是随着年龄的增长&#xff0c;越来越觉得时间过得真的很快啊。转眼间2023年就这么过去了。回看这一年&#xff0c;发现真的做了很多事。 按照惯例&#xff0c;做个总结吧。 获奖 很多人都知道&#xff0c;我去…

百度高级Java面试真题

今年IT寒冬&#xff0c;大厂都裁员或者准备裁员&#xff0c;作为开猿节流主要目标之一&#xff0c;我们更应该时刻保持竞争力。为了抱团取暖&#xff0c;林老师开通了《知识星球》&#xff0c;并邀请我阿里、快手、腾讯等的朋友加入&#xff0c;分享八股文、项目经验、管理经验…

Spring04

一、AOP的概念 AOP 为 (Aspect Oriented Programming) 的缩写&#xff0c;意为&#xff1a;面向切面编程&#xff0c;底层是使用动态代理的技术实现对目标方法的增强和控制访问等功能。 其中AOP中有几个重要的概念: 1、通知:增强的逻辑&#xff0c;或者后期要加入的代码。 2、目…

【js】js解析Token:

一、效果&#xff1a; 二、实现&#xff1a; export function getTokenObject(token) {//通过split()方法将token转为字符串数组,数组中的第二个字符进行解析return token ? JSON.parse(decodeURIComponent(escape(window.atob(token.split(".")[1].replace(/-/g &…

docker Mysql-udf-http

1.Mysql-udf-http镜像已上传到dockerhub中 docker pull heidaodageshiwo/mysql-udf-http:v1 2.启动镜像(默认密码root1234) docker run -tid -p 3306:3306 --namemysql-udf-http --privilegedtrue heidaodageshiwo/mysql-udf-http:v1 3.命令 [rootlocalhost ~]# docker im…

odoo17 | 开发环境设置

前言 开始odoo17开发之前&#xff0c;请先掌握python的基本语法和工具包的使用&#xff0c;以及postgres数据库的安装&#xff0c;和简单的sql使用。以及一些前端的html、css、javascript等前端知识&#xff0c;以及xml、json等数据传输的使用。 本教程同时适用于odoo15-17 …

go语言语法基础

文章目录 前言一、输入和输出常用的字符串格式化符号 二、注释三、Go常用基本语言数据类型数字类型布尔类型字符类型变量与常量数组和切片数组切片 map类型创建map增删改查特别提醒 指针 四、运算符五、条件判断语句if系列switch六、循环语句for循环标准写法死循环while循环do …

Primavera Unifier 项目控制延伸:Phase Gate理论:2/3

阶段Gate的具体内容&#xff1a; 阶段0 根据公司需要和资源现状&#xff0c;决定开展哪些项目。在这个阶段&#xff0c;公司一般需要开展一些脑力风暴或者团队集思广益的活动以获得足够多的点子。一旦团队决定采用某个想法&#xff0c;必须从各个维度去完善它&#xff0c;并使…