Redis数据库(二):Redis 常用的五种数据结构
Redis 能够做到高性能的原因主要有两个,一是它本身是内存型数据库,二是采用了多种适用于不同场景的底层数据结构。
Redis 常用的数据结构支持字符串、列表、哈希表、集合和有序集合。实现这些数据结构的底层数据结构有 6 种,分别是简单动态字符串、双向列表、压缩列表、哈希表、跳表和整数数组。
List、 Hash、Set 和 Sorted Set 这四种数据类型,都有两种底层实现结构。通常情况下,我们会 把这四种类型称为集合类型,它们的特点是一个键对应了一个集合的数据。
那么,有一些问题值得我们去思考:
- 既然 Redis 是键值型数据结构,那么键和值本身之间用什么结构组织?
- 操作集合数据的效率和哪些因素有关?
2.1 键和值用什么数据结构组织?
为了实现从键到值的快速访问,Redis 使用了一个哈希表来保存所有键值对。一个哈希表,其实就是一个数组,数组的每个元素称为一个哈希桶。
因为值本身的类型可以是列表、哈希表等集合类型,因此哈希桶存放的并不是值本身,而是 *key
和 *value
的入口地址。
使用哈希表的好处就是能够在 O(1) 时间内根据 key 查找到相应的 value。但,哈希表的性能并非一直是 O(1)。当需要解决哈希表冲突和再哈希(rehash)时可能会带来性能的下降。
2.1.1 哈希表冲突
哈希表冲突是指根据不同的 key 计算得到了相同的哈希值,就是说有不同的键值对放到了同一个哈希桶当中。因为哈希桶的个数是有限的,因此总会遇到哈希冲突。
解决哈希冲突的方法有多种,Redis 采用的是链式哈希。具体来说,就是同一个哈希桶中的多个元素用一个链表来保存,它们之间通过指针来连接。
链式哈希会带一个问题是,当位于同一个桶中的元素太多时,查询桶中元素的时间复杂度会退化到 O(n),这是我们不愿看到的。解决办法就是对旧的哈希表进行 rehash,将新的哈希值存放在一个更大的哈希桶中。但如果直接进行原地哈希,必然会导致性能急剧下降,解决的办法就是将 rehash 的操作均摊到之后的操作中。
2.1.2 渐进式 rehash
渐进式 rehash 的思想是在拷贝数据时,Redis 仍然正常处理客户端请求,每处理一个请求 时,从哈希表 1 中的第一个索引位置开始,顺带着将这个索引位置上的所有 entries 拷贝 到哈希表 2 中;等处理下一个请求时,再顺带拷贝哈希表 1 中的下一个索引位置的 entries。
这样就巧妙地把一次性大量拷贝的开销,分摊到了多次处理请求的过程中,避免了耗时操作,保证了数据的快速访问。
2.2 操作数据集合的效率
查找一个集合类型的值的过程是:先通过全局哈希表找到对应的哈希桶位置,然后在集合进行增删改查。那么,集合的操作效率与哪些因素有关呢?
首先是与集合底层采用的数据结构有关,例如哈希表的查询时间复杂度要优于链表的。其次是与这些操作本身的执行特点有关,例如读取一个元素和读取一个范围的元素。
2.2.1 底层数据结构的特点
Redis 实现集合类型的底层数据结构有双向列表、整数数组、哈希表、压缩列表和跳表。
哈希表的特点刚才已经介绍过了。双向列表和整数数组比较常见,这里就不再详细展开了。
重点介绍一个压缩列表和跳表。
压缩列表
压缩列表类似于一个数组,数组中的每一个元素都对应保存一个数据。和数组不同的是,压缩列表在表头有三个字段 zlbytes、zltail 和 zllen,分别表示列表长度、列表尾的 偏移量和列表中的 entry 个数;压缩列表在表尾还有一个 zlend,表示列表结束。
在压缩列表中,如果我们要查找定位第一个元素和最后一个元素,可以通过表头三个字段的长度直接定位,复杂度是 O(1)。而查找其他元素时,就没有这么高效了,只能逐个查找,此时的复杂度就是 O(N) 了。
跳表
跳表在链表的基础上,增加了多级索引,通过索引位置的几个跳转,实现数据的快速定位,跳表的查询过程如下图所示:
以上五种数据结构的时间复杂度如下表所示:
2.2.2 不同操作的复杂度
集合类型的操作方法很多,例如获取单个元素、多个元素、判断某个元素是否在集合当中。而不同数据结构的同一种操作方法的时间复杂度不同,因此有必要了解不同操作方法的时间复杂度。
- 单元素操作时间复杂度为 O(1);
- 范围操作比较耗时。当返回一个范围内的元素时,例如返回集合、List 某个范围的元素,时间复杂度为 O(N)。
- 统计元素个数比较高效。压缩列表、双向列表、整数数组这些数据结构中专门记录了元素的个数,统计执行效率较高。
- 特殊位置的元素操作效率与数据结构密切相关。例如对于 List 而言,在头尾进行操作元素的时间复杂度为 O(1),而在中间位置操作元素的时间复杂度为 O(N)。
2.3 使用数据结构的建议
选择 Redis 的数据结构时,需要综合考虑数据的特点、操作需求、内存占用和性能要求等多个因素。
选择 Redis 数据结构时,应该考虑以下几个因素:
-
数据访问模式
• 字符串(String):适用于简单的 key-value 存储,比如缓存用户会话、计数器、或是简单的数据存取。
• 哈希(Hash):适合存储对象、结构化数据,如用户信息、商品详情等。哈希允许在单一 key 下保存多个字段(字段值对),非常适合于存储较小的对象。
• 列表(List):适合存储有序的集合,比如消息队列、任务队列、用户操作日志等。支持推入、弹出操作,符合生产者-消费者模型。
• 集合(Set):适合存储无序且唯一的元素集合,用于去重操作、标签分类等。例如,存储用户订阅的标签列表,或是某些“推荐系统”的推荐项。
• 有序集合(Sorted Set):适合存储带有权重的有序数据,支持根据分数进行排序。适用于排行榜、优先级队列、延迟队列等应用场景。 -
性能要求
• 存储效率:不同数据结构的存储方式和空间效率不同。比如,集合(Set)适合去重,哈希(Hash)适合存储对象,如果需要存储大量字段和小值数据,使用哈希结构可以节省内存。
• 操作效率:不同数据结构在操作时的复杂度也不同。一般来说,字符串操作最简单,复杂度为 O(1),而有序集合(Sorted Set)的某些操作,如添加、删除元素的复杂度可能为 O(log N)。 -
数据大小与访问频率
• 如果需要频繁对数据进行增、删、改、查等操作,选择操作复杂度较低的数据结构,例如字符串和哈希。
• 对于大数据量和高并发的场景,考虑 Redis 的内存消耗和性能瓶颈。比如,HyperLogLog 在大数据量去重时非常高效。 -
使用场景
• 缓存:大多数缓存场景使用字符串(String)或哈希(Hash)。例如,缓存一整个页面或用户信息。
• 队列:使用列表(List)或有序集合(Sorted Set)来实现消息队列、任务调度等。
• 去重与标签:集合(Set)适用于去重和标签管理。
• 排行榜与优先级队列:使用有序集合(Sorted Set)存储带权重的数据,并根据分数进行排序。 -
数据过期与持久化
• Redis 提供了 EXPIRE 命令来为 key 设置过期时间,但不同数据结构的持久化策略可能不同。根据业务需求决定是否需要启用 Redis 的持久化机制(RDB 或 AOF),以及数据结构的持久化需求。
总结来说,选择 Redis 数据结构的关键是结合具体的业务需求、访问模式、性能要求等因素来进行权衡。在有些情况下,可能还需要多种数据结构的组合使用,以达到最佳效果。
实际上,在 Redis 7.4 版本中,已经支持 9 种数据结构,分别是String、Hash、List、Set、Sorted set、Stream、Bitmap、Bitfield以及Geospatial。后四种数据结构会专门再写一篇文章进行介绍。
觉得有用可以点个赞。
相关文章:

Redis数据库(二):Redis 常用的五种数据结构
Redis 能够做到高性能的原因主要有两个,一是它本身是内存型数据库,二是采用了多种适用于不同场景的底层数据结构。 Redis 常用的数据结构支持字符串、列表、哈希表、集合和有序集合。实现这些数据结构的底层数据结构有 6 种,分别是简单动态字…...

【计组】实验五 J型指令设计实验
目录 一、实验目的 二、实验环境 三、实验原理 四、实验任务 代码 一、实验目的 1. 理解MIPS处理器指令格式及功能。 2. 掌握lw, sw, beq, bne, lui, j, jal指令格式与功能。 3. 掌握ModelSim和ISE\Vivado工具软件。 4. 掌握基本的测试代码编写和FPGA开发板使用方法。 …...

ubuntu 本地部署deepseek r1 蒸馏模型
本文中的文件路径或网络代理需要根据自身环境自行删改 一、交互式chat页面 1.1 open-webui 交互窗口部署:基于docker安装,且支持联网搜索 Open WebUI 是一个可扩展、功能丰富且用户友好的自托管 AI 平台,旨在完全离线操作。它支持各种 LLM…...
RestTemplate Https 证书访问错误
错误信息 resttemplate I/O error on GET request for “https://21.24.6.6:9443/authn-api/v5/oauth/token”: java.security.cert.CertificateException: No subject alternative names present; nested exception is javax.net.ssl.SSLHandshakeException: java.security.c…...

MySQL内存使用率高且不释放问题排查与总结
背景 生产环境mysql 5.7内存占用超过90%以上,且一直下不来。截图如下: 原因分析 1、确定mysql具体的占用内存大小,通过命令:cat /proc/Mysql进程ID/status查看 命令执行后的结果比较多(其他参数的含义想了解可参考这…...
mysql8 从C++源码角度看sql生成抽象语法树
在 MySQL 8 的 C 源码中,SQL 语句的解析过程涉及多个步骤,包括词法分析、语法分析和抽象语法树(AST)的生成。以下是详细的解析过程和相关组件的描述: 1. 词法分析器(Lexer) MySQL 使用一个称为…...

【DeepSeek】DeepSeek概述 | 本地部署deepseek
目录 1 -> 概述 1.1 -> 技术特点 1.2 -> 模型发布 1.3 -> 应用领域 1.4 -> 优势与影响 2 -> 本地部署 2.1 -> 安装ollama 2.2 -> 部署deepseek-r1模型 1 -> 概述 DeepSeek是由中国的深度求索公司开发的一系列人工智能模型,以其…...

【C++】多态原理剖析
目录 1.虚表指针与虚表 2.多态原理剖析 1.虚表指针与虚表 🍪类的大小计算规则 一个类的大小,实际就是该类中成员变量之和,需要注意内存对齐空类:编译器给空类一个字节来唯一标识这个类的对象 对于下面的Base类,它的…...

【Rust自学】20.4. 结语:Rust学习一阶段完成+附录
喜欢的话别忘了点赞、收藏加关注哦,对接下来的教程有兴趣的可以关注专栏。谢谢喵!(・ω・) 20.4.1. 总结 Rust初级学习之旅终于完成了!恭喜! 包括这篇文章,我们使用了110篇文章来学习Rust。 真…...
pytorch引用halcon写数据集
****加粗样式虽然啰嗦一点,但好歹halcon自己熟悉,不会忘记,用os 和 pil会导致脑子记得东西太多 import halcon as ha import torch from torch.utils.data import Datasetpath0 rE:\BaiduNetdiskDownload\cell class MyDataset(Dataset):de…...

让文物“活”起来,以3D数字化技术传承文物历史文化!
文物,作为不可再生的宝贵资源,其任何毁损都是无法逆转的损失。然而,当前文物保护与修复领域仍大量依赖传统技术,同时,文物管理机构和专业团队的力量相对薄弱,亟需引入数字化管理手段以应对挑战。 积木易搭…...

aarch64 Ubuntu20.04 安装docker
安装 docker 依赖项:sudo apt-get update sudo apt-get install apt-transport-https ca-certificates curl gnupg lsb-release添加 Docker GPG 密钥:curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo gpg --dearmor -o /usr/share/keyr…...

JAVA:CloseableHttpClient 进行 HTTP 请求的技术指南
1、简述 CloseableHttpClient 是 Apache HttpComponents 提供的一个强大 HTTP 客户端库。它允许 Java 程序与 HTTP/HTTPS 服务交互,可以发送 GET、POST 等各种请求类型,并处理响应。该库广泛用于 REST API 调用、文件上传和下载等场景。 2、特性 Close…...

Mac上搭建k8s环境——Minikube
1、在mac上安装Minikube可执行程序 brew cask install minikub 安装后使用minikube version命令查看版本 2、安装docker环境 brew install --cask --appdir/Applications docker #安装docker open -a Docker #启动docker 3、安装kubectl curl -LO https://storage.g…...

经典排序算法复习----C语言
经典排序算法复习 分类 交换类 冒泡快排 分配类 计数排序基数排序 选择类 选择排序 堆排序 归并类 归并排序 插入类 直接插入排序 希尔排序 折半插入排序 冒泡排序 基于交换。每一轮找最大值放到数组尾部 //冒泡排序 void bubSort(int* arr,int size){bool sorte…...

自动驾驶数据集三剑客:nuScenes、nuImages 与 nuPlan 的技术矩阵与生态协同
目录 1、引言 2、主要内容 2.1、定位对比:感知与规划的全维覆盖 2.2、数据与技术特性对比 2.3、技术协同:构建全栈研发生态 2.4、应用场景与评估体系 2.5、总结与展望 3、参考文献 1、引言 随着自动驾驶技术向全栈化迈进,Motional 团…...
[LUA ERROR] bad light userdata pointer
Cocos2d项目,targetSdkVersion30,在 android 13 设备运行报错: [LUA ERROR] bad light userdata pointer ,导致黑屏。 参考 cocos2dx 适配64位 arm64-v8a 30 lua 提示 bad light userdata pointer 黑屏-CSDN博客的方法 下载最新的Cocos2dx …...
【Java八股】JVM
JVM 1. jvm内存区域分为哪些部分 线程私有的:程序计数器、虚拟机栈、本地方法栈 程序计数器:指示当前线程执行到的字节码文件的行号,是线程切换后保证线程能恢复到正确的执行位置的关键 虚拟机栈:用于存储方法调用的数据&…...
集成学习(一):从理论到实战(附代码)
一、引言 在机器学习领域,打造一个独立、强大的算法是解决问题的关键。然而,集成学习提供了一种不同的视角:通过组合多个“弱”学习器来创建一个更强大的模型。本文探讨集成学习的思想、方法及其应用。 二、机器学习 vs 集成学习思想 传统…...
Netty:高性能网络应用框架的深度解析
引言 Netty 是由 JBoss 提供的一个开源的 Java NIO 客户端/服务器框架,它用以快速开发网络应用程序,如协议服务器和客户端。它的设计目标是提供异步事件驱动的网络应用程序框架,支持高效的网络通信和数据处理。Netty 在性能、可扩展性、安全…...

Qt/C++开发监控GB28181系统/取流协议/同时支持udp/tcp被动/tcp主动
一、前言说明 在2011版本的gb28181协议中,拉取视频流只要求udp方式,从2016开始要求新增支持tcp被动和tcp主动两种方式,udp理论上会丢包的,所以实际使用过程可能会出现画面花屏的情况,而tcp肯定不丢包,起码…...

以下是对华为 HarmonyOS NETX 5属性动画(ArkTS)文档的结构化整理,通过层级标题、表格和代码块提升可读性:
一、属性动画概述NETX 作用:实现组件通用属性的渐变过渡效果,提升用户体验。支持属性:width、height、backgroundColor、opacity、scale、rotate、translate等。注意事项: 布局类属性(如宽高)变化时&#…...
IGP(Interior Gateway Protocol,内部网关协议)
IGP(Interior Gateway Protocol,内部网关协议) 是一种用于在一个自治系统(AS)内部传递路由信息的路由协议,主要用于在一个组织或机构的内部网络中决定数据包的最佳路径。与用于自治系统之间通信的 EGP&…...
ssc377d修改flash分区大小
1、flash的分区默认分配16M、 / # df -h Filesystem Size Used Available Use% Mounted on /dev/root 1.9M 1.9M 0 100% / /dev/mtdblock4 3.0M...
【决胜公务员考试】求职OMG——见面课测验1
2025最新版!!!6.8截至答题,大家注意呀! 博主码字不易点个关注吧,祝期末顺利~~ 1.单选题(2分) 下列说法错误的是:( B ) A.选调生属于公务员系统 B.公务员属于事业编 C.选调生有基层锻炼的要求 D…...

ElasticSearch搜索引擎之倒排索引及其底层算法
文章目录 一、搜索引擎1、什么是搜索引擎?2、搜索引擎的分类3、常用的搜索引擎4、搜索引擎的特点二、倒排索引1、简介2、为什么倒排索引不用B+树1.创建时间长,文件大。2.其次,树深,IO次数可怕。3.索引可能会失效。4.精准度差。三. 倒排索引四、算法1、Term Index的算法2、 …...
OpenPrompt 和直接对提示词的嵌入向量进行训练有什么区别
OpenPrompt 和直接对提示词的嵌入向量进行训练有什么区别 直接训练提示词嵌入向量的核心区别 您提到的代码: prompt_embedding = initial_embedding.clone().requires_grad_(True) optimizer = torch.optim.Adam([prompt_embedding...

IT供电系统绝缘监测及故障定位解决方案
随着新能源的快速发展,光伏电站、储能系统及充电设备已广泛应用于现代能源网络。在光伏领域,IT供电系统凭借其持续供电性好、安全性高等优势成为光伏首选,但在长期运行中,例如老化、潮湿、隐裂、机械损伤等问题会影响光伏板绝缘层…...

安宝特方案丨船舶智造的“AR+AI+作业标准化管理解决方案”(装配)
船舶制造装配管理现状:装配工作依赖人工经验,装配工人凭借长期实践积累的操作技巧完成零部件组装。企业通常制定了装配作业指导书,但在实际执行中,工人对指导书的理解和遵循程度参差不齐。 船舶装配过程中的挑战与需求 挑战 (1…...

视觉slam十四讲实践部分记录——ch2、ch3
ch2 一、使用g++编译.cpp为可执行文件并运行(P30) g++ helloSLAM.cpp ./a.out运行 二、使用cmake编译 mkdir build cd build cmake .. makeCMakeCache.txt 文件仍然指向旧的目录。这表明在源代码目录中可能还存在旧的 CMakeCache.txt 文件,或者在构建过程中仍然引用了旧的路…...