redis之为什么那么快

news/2024/5/8 0:20:51/文章来源:https://blog.csdn.net/wang0907/article/details/127119487

写在前面

在面试中关于redis经常被问到一个问题就是redis为什么快,本文就一起从其底层的数据结构实现来分析下,为什么快,哪些快,哪些慢,哪些操作会导致慢等,下面我们就开始吧!

1:为什么快?

从大的方面来说,主要有以下两点:

1:基于内存的操作,内存的读写速度非常高,大概在百万分之一秒的级别
2:底层的优秀数据结构的支持,这点最为重要

关于第一点,没有什么需要具体说明的,这是内存本身提供的天然优势,主要还是要分析2,底层数据结构的支持。

2:数据是怎么存储的?

我们知道redis是一种kv数据库,这种kv结构redis是使用哈希表 存储的,具体的数据存储在哈希桶中,其中哈希桶中entry结构是(*key,*value)的键值对,其中*key是指向具体key的指针,*value是指向具体值的指针,可能如下结构:

在这里插入图片描述

当有哈希冲突时通过链表解决冲突,可能像下图:

在这里插入图片描述

所以我们可以看到,当我们执行一个通过key查询value的操作时,找到value是很快的,时间复杂度是O(1),更多的查询时间是消耗在从value中找到具体的我们需要的值了,所以,我们就需要具体来看下value都有哪些数据类型了,以及这些数据类型底层支持的数据结构是什么样的。

3:value数据类型以及底层数据结构

value的类型和底层数据结构关系如下图:

在这里插入图片描述

接下来我们看下具体每种数据结构。

3.1:简单动态字符串

TODO 补充简单动态字符串的具体实现

3.2:双向链表

双向链表是我们日常工作中非常常见的数据结构,有些类似于常用的交通工具火车,两侧都是车头,也都是车尾,参考下图:

在这里插入图片描述

3.3:压缩列表

压缩列表并不像数组,链表,哈希表等,是基础的数据结构,而是redis自创的一种数据结构赞创新精神!!!,有些类似于数组,但是数组中每个元素的长度是由数组中最大的那个元素长度决定的,如我们定义一个String数组,其中最大一个元素的数据长度是20字节,则其他每个元素占用内存长度都是20字节,虽然其实际的长度是小于20字节的,这就造成了内存空间的浪费,redis为了解决这个问题,就引入了压缩列表,假设我们有如下的数组:

在这里插入图片描述

该数组长度为5,其中索引位4的元素长度是10,所以总长度是40,但其实存储所有的元素只需要1+2+3+4+20=30,浪费了10个字节的内存空间,如果是使用压缩列表的话其结构如下:

在这里插入图片描述

格式是元素数,元素长度,元素,元素长度,元素。。。,其中通过每个元素长度我们就能知道下一个元素通过怎样的内存偏移量来获取了。此时的数据总长度是34,节省了6字节的内存空间。这里如果是最大元素要比其他元素长度大的多的话,则内存优化的效果会更加明显。

压缩列表数据查找,插入,删除的时间复杂度都是O(n),所以对于底层数据结构是压缩列表的数据结构在使用上要格外小心,避免出现性能问题。

3.4:哈希表

参考数据结构之哈希算法 。

3.5:跳表

参考数据结构之跳表 。

查找,插入,删除的时间复杂度都是O(logn),效率很好。

3.6:整数数组

用在哈希表中。

接下来我们再看下常用的操作的时间复杂度是怎样的,以此来看其快和慢

4:常用操作分析

先来看下不同数据结构的时间复杂度。

在这里插入图片描述

我们通过redis提供的操作接口,命令 来分析下操作的时间复杂度。

4.1:String#get和set

127.0.0.1:6379> set name jack
OK
127.0.0.1:6379> get name
"jack"

set操作只需要将对应的kv设置到全局哈希表中,get操作从全局哈希表中获取的value值就是我们需要的目标值,并不需要额外的解析,所以二者操作的时间复杂度都是O(1)。

4.2:String#mget和mset

get和set的批量版本,m,即multi,假设批量的个数是M,则此二操作的时间复杂度是O(M)。

4.3:Hash#hget和hset

127.0.0.1:6379> hset myhash name "zhangsan"
(integer) 0     
127.0.0.1:6379> hget myhash name
"zhangsan"      

二者都是基于哈希表的操作,所以是常量时间复杂度O(1)。

4.4:Hash#hmget和hmset

hget好hset的批量版本,m,即multi,假设批量的个数是M,则此二操作的时间复杂度是O(M)。

4.5:Set#sadd

127.0.0.1:6379> sadd myset "aaa"
(integer) 1
127.0.0.1:6379> sadd myset "bbb"
(integer) 1

基于哈希的操作,时间复杂度为O(1)。

4.6:Set#srandmenber

随机返回一个元素。

127.0.0.1:6379> sadd myset "bbb"
(integer) 1
127.0.0.1:6379> SADD myset one two three
(integer) 3     
127.0.0.1:6379> srandmember myset
"three"
127.0.0.1:6379> srandmember myset
"aaa"
127.0.0.1:6379> srandmember myset
"two"

时间复杂度O(1)。

4.7:hash#hgetall

redis> HSET myhash field1 "Hello"
(integer) 1
redis> HSET myhash field2 "World"
(integer) 1
redis> HGETALL myhash
1) "field1"
2) "Hello"
3) "field2"
4) "World"

尽管是哈希结构,但是需要遍历,所以时间复杂度是O(n),实际工作中最好不要使用。

4.8:set#smembers

redis> SADD myset "Hello"
(integer) 1
redis> SADD myset "World"
(integer) 1
redis> SMEMBERS myset
1) "World"
2) "Hello"

尽管是哈希结构,但是需要遍历,所以时间复杂度是O(n),实际工作中最好不要使用。

最后我们可以通过下图来看下不同的时间复杂度和查询需要的时长的关系图:

在这里插入图片描述

其中除常量时间复杂度O(1)外,只有对数时间复杂度O(logn)随着数据量的增加,时间增长不是非常明显,其他的如线性时间复杂度O(n),数据量越大,性能下降的就非常厉害了,所以当某操作的时间复杂度是O(n)以及比起更加糟糕的时间复杂度时一定要格外注意,避免因为数据量过大出现性能问题。

写在后面

参考文章列表:

redis 命令手册 。

redis 数据结构之哈希算法 。

数据结构之跳表 。

数据结构之跳表 。

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

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

相关文章

【无标题】近几年攻防演练攻击队典型突破的例子

蓝队经典攻击实例 实战攻防演练中红队网络的部署情况各有特点,蓝队也会根据攻 击目标的不同而采取不同的攻击策略和手段。下面几个案例展示的就 是针对红队网络的不同薄弱点采取的不同的典型攻击策略与方法手 段。 正面突破:跨网段控制工控设备 某企业…

C#面向对象程序设计课程实验一:实验名称:C#语言基础、程序流程控制

C#面向对象程序设计课程实验一:实验名称:C#语言基础、程序流程控制实验内容:C#语言基础、程序流程控制一、 实验目的二、实验环境三、实验内容四、实验总结实验内容:C#语言基础、程序流程控制 一、 实验目的 (1)练习 C#变量声明和…

simulink-自定义模块GUI回调函数

目录 一、创建simulink模块 二、自定义GUI步骤 2.1 设计组件界面信息 2.2 GUI控件介绍 2.2.1 Parameter参数配置组件 2.2.2 Container参数配置组件 2.2.3 Display参数配置组件 2.2.4 Action参数配置组件 2.3 控件回调函数使用方法 三、设置Help信息 四、获取配置控件参数 4.…

ubuntu 搭建RKNN-Toolkit环境

1. github下载官方的RKNN-Toolkit项目包 地址:https://github.com/rockchip-linux/rknn-toolkit 然后还需要下载rknn-toolkit包,GitHub下方有链接: 各种版本的官方下载: https://github.com/rockchip-linux/rknn-toolkit/relea…

实现有效控制项目进度,需要做好这些工作

制定出切合的项目计划是执行的重要基础,计划制定的过程同时也是计划逐步细化的过程, 进度计划的贯彻是计划实施的第一步,也是最关键的一步。 一、实现有效控制项目进度,需要做好以下工作: 项目计划,决定…

JavaScript · 9:数据类型转换 隐式转换

总览 1.数据转换为string类型 2.数据转换为Number数字类型 3.数据转换为boolean类型 一、将数据转换为string类型 1.方法 最常用的是“加号拼接字符串”,也就是 隐式转换 ,其中用于拼接的字符串内容可以为空 二、将数据转换为number数值类型 1.方…

Vue 响应式实现原理深入浅出

前言 vue 是一个易上手的框架,许多便捷功能都在其内部做了集成,其中最有区别性的功能就是其潜藏于底层的响应式系统。组件状态都是响应式的 JavaScript 对象。当更改它们时,视图会随即更新,这让状态管理更加简单直观。那么&#…

既要又要的正则匹配规则

目录 1 背景 2 浅谈 3 分析 3.1 如何识别成整体块? 3.1.1 正则匹配整体块 3.1.2 “ - ”开头“ - ”结尾 3.1.3 模糊匹配不行,采取精准匹配 3.2 如何作为整体块显示? 3.3 光标不可以中间插入 4 效果展示 5 参考代码 1 背景 在上面…

BorderDet:Border Feature for Dense ObjectDetection

原文链接: 概述 密集物体检测依赖于滑动窗口,在图像的规则网格上预测物体,使用点的特征图来生成预测边界框,但由于边界信息不明确导致无法进行准确定位。本文提出了“Border-Align”的操作来从边界点中提取特征来增强点特征。基于…

Jmeter初始学习

Jmeter是一款优秀的开源性能工具,官网文档地址:http://jmeter.apache.org/usermanual/index.html 一、优点 1.开源工具,可扩展性非常好; 2.高可扩展性,用户可自定义调式相关模块代码; 3.精心简单的GUI设…

iOS App更换图标Logo(本地更换)

1.各大购物平台在节假日都是更换App Icon图标 通常有两种方式:1.每换一个新的图标,需要重新上一次AppStore; 2.在项目里预留好未来需要更换的图标,用api触发(或者本地时间判断自动更换) 两种方法各有利弊,第一种 弊&…

「喜迎华诞」手把手教你用微信小程序给头像带上小旗帜

文章目录一、文章前言二、实现原理三、开发步骤四、完整代码五、国庆临近,祝祖国永远繁荣昌盛!一、文章前言 2022年是新中国成立73周年,在这个举国欢庆的日子里,让我们给头像上加上小红旗,迎国庆换新颜,一起…

视频倒放怎么制作?快来学会这几个简单的方法

众所周知,如果我们想要让视频更具有观赏性的话,少不了用视频倒放功能来制作视频。不过还是有很多小伙伴不知道视频倒放怎么制作? 下面我就来手把手教你们视频倒放的制作方法,你们快来看看吧! 方法一:提词全…

Monaco Editor教程(五): 实现同时多文件编辑,tab切换

背景 上一篇我们讲解了如何设置编辑器的值,获取编辑器的值,以及监听编辑器的内容修改。这些功能对于基础的单文件修改,一次只修改一个文件的业务场景比较友好。但如果是复杂的场景,比如WEB IDE,同时打开一个项目的多个…

聊聊SQL注入

明天是国庆1001,祝大家国庆节快乐!!!这个月还有属于程序员的节日:1024SQL注入问题概述:首先SQL注入是一个非常危险的操作,很可能被一些不怀好意的人钻空导致我们系统出现异常等状况,比如数据库遭到破坏或被入侵。原因:使用JDBC的Statement语句添加SQL语句由于我们的JD…

直播电商开发,源码无加密

随着直播电商的流行,很多企业开始使用商场电商直播系统,该企业使用电商直播系统的优势具体体现在哪里?下面由零七科技小编为您总结企业电商直播系统的优点。 使用电商直播系统的优点: 1、全面展示商品风格和效果。 与在线平台的…

【Django-rest-framework框架】第04回 视图集

目录1. 两个视图基类1.1 GenericAPIview属性和方法1.2 基于APIView写5个接口1.3 基于GenericAPIview写5个接口2. 5个视图扩展类3. 9个视图子类4. 视图集5. 源码分析ViewSetMixin6. 总结7 继承关系画出来,有哪些常用属性或方法写出来 1. 两个视图基类 1.1 GenericAPIview属性和…

【redis】7.1 分布式架构概述(章节介绍)

分布式架构概述 请求业务比较长(耗时业务),需要分布式系统。 1. 本章节内容 分布式缓存中间件Redis分布式会话与单点登录分布式搜索引擎Elasticsearch分布式文件系统分布式消息队列分布式锁数据库读写分离与分库分表数据库表全局唯一主键i…

迭代器并不全是指针,list的迭代器与vector和string的有什么不一样,让博主告诉你其底层原理!

链表的模拟实现 文章目录链表的模拟实现一、list的基本架构🤖_list_node基本构架--双向带头循环链表二、list的迭代器--重点🐱‍👤list迭代器的基本架构构造函数--node*封装operator*()--得到值operator!()--跟另一个迭代器进行比较operator(…

xLua热更新(一)xLua基本使用

一、什么是xLua xLua为Unity、 .Net、 Mono等C#环境增加Lua脚本编程的能力,借助xLua,这些Lua代码可以方便的和C#相互调用。 xLua是用来实现Lua代码与C#代码相互调用的插件。我们可以借助这个插件来实现热更新方案。 那么为什么要选择Lua实现热更新呢&am…