为什么redis的zset用跳跃表而不用b+ tree?

news/2024/5/9 2:36:24/文章来源:https://blog.csdn.net/f80407515/article/details/129136998

这两天有小伙伴问我一个问题,为什么redis的zset用跳跃表,不用b+ tree?

我先不说结论,我先说下 跳跃表 和B+tree 。

跳跃表

在之前的 《redis源码阅读-zset》 中,已经详解了zset的使用跳跃表的源码,今天借用下之前的图片。

image-20230219181500094

zset在演化为跳跃表以后,主要有两块

  • 一块以*dict 存储的 元素与分值的hash映射
  • 一块以*zsl 存储的跳跃表的信息
    • 关键是*header的一个64级的数组(可以理解为hashmap的桶结构)
    • 第0层是所有数据的以score排序的双向链表
    • 第1~63层是是构建出来的跳跃表,也是双向链表
    • 在插入数据的时候会随机生成 层级(每一个元素都有可能是0~63级),从上到下查找并插入
    • 在查找数据的时候,有分值直接查,没分值先从*dict获取对应元素的分值

在这里我们一定要注意几个点,

  • 元素的层级结构
  • 双向链表

举个例子,见下图

image-20230219184543704

插入:

  • 假如有socre=30、25、45 这三个元素,最高层级2层

  • 插入score=30的时候,随机出了3级索引,

    • 会把header节点第2层的指针l[2]指向该元素,同时往下1层查
    • 会把第1层的score=20的指针l[1]指向该元素,同时顺着score=20往下一层查
    • 找到score=30的插入顺序
  • 插入score=60的时候,随机出了4级索引

    • 会把header节点第3层的指针指l[3]向该元素,同时顺着header往下1层查
    • 会把第2层score=30的节点的指针l[2]指向该元素,同时顺着score=30往下1层查
    • 会把第2层score=30的节点的指针l[1]指向该元素,同时顺着score=30往下1层查
  • 然后插入score=45的时候,随机出了3级索引

    • 从header节点第4层查,发现score=60大于45,顺着header往下1层查
    • 查到header的l[2]层,发现45>40,ok,定位到score=30
    • score=30的l[2]指向60,将该指针指向45,同时将45的l[2]指向score=60
    • score=30的l[1]指向60,将该指针指向45,同时将45的l[2]指向score=60

理论上最多从*header的最高层到最低层,然后链表查询

删除:

  • 定位到元素以后,通过双向链表,获取到前驱和后继节点,直接改变指针即可

时间复杂度:

  • 跳跃表最坏的时间复杂度为O(n) (索引高度只随机出一层的时候)

B+ Tree

之前在 记一次生产慢sql查询的解决 和InnoDB存储引擎存储结构详解-实战篇中介绍了B+ Tree的结构,以及

image-20230219190633721

首先,我们先了解下:

  • InnoDB是以数据页为一个存储单元,默认16kb;
  • 非叶子节点存储索引,叶子节点存储数据
  • 一个bigint的索引,在一个索引页中有878条记录,一个数据页中123条数据(数据量大小和表结构有关,我贴的是我的试验数据)
  • 默认mysql三层最多数据页有 878*878 约77万个数据页
    • 通过innodb_space -s ibdata1 -T innodb_space/t_user_info -F 1 space-index-fseg-pages-summary 可以看到具体的层级
    • 按照我试验的表结构,三层可以容纳 77*123= 9471w条数据
  • 当时灌了5000万条数据占磁盘7.7GB

插入:

如果是数值类型,非自增插入

  • 通过底层索引,二分查找,最多8次能定位到第2层的索引页
  • 然后在第二层索引页里,通过二分,再最多进行8次定位到第3层的数据页
  • 在数据页中通过二分查找,最多再6次定位到数据
  • 如果数据页过大,还得进行页分裂

如果是自增插入,只需要在内存中缓存每层的最后节点,能O(n)定位到。

如果是字符串呢?效率会进一步退化

删除

按根据主键删除

  • 和数值型非自增插入的查询效率一样
  • 如果中间删除数据多了,导致相邻的数据页过小,还会进行页合并的操作

如果非主键,先定位到主键再回表。

时间复杂度

  • 平均时间复杂度为O(logn)

分析

相同点(以score和数据库主键id相比)

  • 最下面一层都是顺序的,而且是双向链表
  • 都可以通过二分查找查找数据

不同点

  • B+ Tree的结构是平衡的,层级默认3级,时间复杂度为O(logn)
  • zset的跳表数据结构,最高64层,最矮就1层,每个score的对应的层级都是随机的,时间复杂度最差为O(n)
  • 跳表一个节点存储一条数据
  • B+ Tree是以页为单位存储索引和数据
  • 隐性不同:
    • redis是纯内存,无磁盘IO
    • mysql是内存+磁盘 ,如果索引都在磁盘,需要3次IO,如果树的层级高了,需要的IO更多,效率更低
  • B+ Tree 需要保持树的平衡,会有一系列的分裂与合并(顺序写可以忽略)
  • zset的跳表插入数据简单,随机出来层了,定位到以后改个链表节点即可

总结

  • redis设计本身使用的是极简思想,跳跃表的操作,比二叉树简单,不需要考虑平衡,实现起来也简单,我觉的这个是重点
  • redis是纯内存操作,不需要考虑磁盘IO的次数(一个*header可以理解为一个数据页,只不过是在内存里)
  • MySQL为了持久化,需要考虑磁盘IO,利用数据页,系统缓存,减少磁盘的操作顺序

如果这个问题反过来就好解释了,MySQL为什么用B+Tree 而不用跳表

  • 层低,磁盘IO少
  • 性能稳定
    • 平衡
    • 到达每一个叶子节点的路径都固定
  • 就上面的两个,实现复杂度高了也无所谓

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

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

相关文章

hadoop3.*集群搭建,小白必看

hadoop广义上讲是一个大数据生态圈,接受大量处理、处理大量数据的一个全套的框架!hadoop3.x版本以后,主要有三大模块,HDFS、YARN、mapReduce这三大核心组成!什么是HDFS?分布式文件系统,hadoop集群的功能类…

数值方法笔记4:插值、近似和拟合

1. 插值1.1 插值的一些概念1.1.1 插值的定义1.1.2 插值的存在性1.1.3 插值的误差分析1.2 拉格朗日插值(Lagrange Interpolation)1.2.1 拉格朗日插值误差分析1.3 Newton多项式插值1.3.1 Newton多项式插值误差分析1.4 Chebyshev多项式确定插值点1.4.1 Chebyshev多项式性质1.5 有理…

内存映射(1)

内存映射 将磁盘文件中的数据映射到内存,用户通过修改内存就能修改磁盘文件 相关的系统调用: void *mmap() 功能:将一个文件或设备的数据映射到内存中 参数: void *addr : NULL 由内核指定length : 要映射的数据长度,…

JUC并发编程——进程与线程

目录一、进程和线程的概念1.1 进程1.2 线程1.3 进程与线程对比二、并行和并发的概念三、线程基本应用3.1 多线程应用——异步调用一、进程和线程的概念 1.1 进程 ● 程序由指令和数据组成,但这些指令要运行,数据要读写,就必须将指令加载至 …

【Mysql系列】Mysql之ACID实现原理

ACID 原子性 事务不可分割,要么全部执行,要么都不执行。原理是使用undo log。undo log,当事务对数据库进行修改的时候,会生成对应的undo log。 持久性 事务提交后,对于数据库的改变是永久性的。实现原理通过redo l…

超详细解读!数据库表分区技术全攻略

更多内容可以关注微信公众号:老程序员刘飞 分区的定义 分区是一种数据库优化技术,它可以将大表按照一定的规则分成多个小表,从而提高查询和维护的效率。在分区的过程中,数据库会将数据按照分区规则分配到不同的分区中&#xff0…

排序算法-java实现

文章目录冒泡排序选择排序插入排序快速排序希尔排序冒泡排序 原理: 依次比较两个相邻的元素,如果它们顺序错误就把它们交换过来。 时间复杂度: 若文件的初始状态是正序的,一趟扫描即可完成排序。所需的关键字比较次数C和记录移…

graphviz:实现图文件的可视化

1. graphviz下载安装 参考的是这篇文章:https://blog.csdn.net/qq_37085158/article/details/126421102 graphviz的下载地址为:https://graphviz.org/download/ 2. graphviz的使用步骤 将edge文件转化成dot文件WinR,输入cmd,在…

linux rsync服务端安装和windows客户端备份

安装:yum install -y rsync 密码内容:zhangsan:123456 配置文件:/etc/rsyncd.conf内容 # /etc/rsyncd: configuration file for rsync daemon mode # See rsyncd.conf man page for more options. # configuration example: uid root gi…

LVGL Styles

LVGL StylesGet started按钮添加标签按钮添加风格滑动条值显示StylesSize stylesBackground stylesBorder stylesOutline stylesShadow stylesImage stylesArc stylesText stylesLine stylesGet started 按钮添加标签 /*** brief 按钮事件回调函数* param e */ void btn_eve…

网络有线无线配置

一、需求 在无线接入区内,当Lsw1的上联口出现故障时,需要通过AP1-LSw1-LSw2-LSw3的路径访问公网server3。这是因为AP1通过无线网连接到LSw1,而LSw1与LSw3之间的链路出现故障,无法直接访问公网server3。因此,流量需要通…

一文说清WMS系统与MES系统,SRM系统,ERP系统集成的好处

由于制造过程的多样性、复杂性、业务流程的多样性和复杂性,因此,制造企业的信息化系统包括WMS、SRM、MES等管理系统,但它们的管理方向却各不相同,例如WMS这个是管理仓库、 SRM是管理公司的供应商、 MES是管理车间的生产制造的等等…

决策树、随机森林、GBDT、XGBoost

文章目录 1. 引入 1.1 决策树1.2 随机森林1.3 GBDT(Gradient Boosting Decision Tree)梯度提升决策树1.4 XGBoost(eXtreme Gradient Boosting)极端梯度提升2. 代码实现 2.1 决策树&随机森林&GBDT&XGBoost 2.1.1 分类2.1.2 回归2.1.3 显示模…

SpringCloud(二)配置中心

配置中心Nacos配置中心多环境共享Nacos集群搭建Nacos配置中心 作用: 统一配置管理配置自动刷新,热更新 实现: 统一配置管理 在nacos服务端,配置管理配置列表中新建配置了解配置获取的步骤: 项目启动->读取nacos中…

全开源无加密的RuleApp文章社区APP客户端源码

内容目录一、详细介绍二、效果展示1.部分代码2.效果图展示三、学习资料下载一、详细介绍 开源无加密的文章社区客户端源码分享 RuleApp文章社区,VIP会员,写作投稿积分商城,付费模块集成,多平台兼容这是一款开源免费,界…

最全es6数组方法

1.arr.push()从后面添加元素,返回值为添加完后的数组的长度 let arr [1,2,3,4,5] console.log(arr.push(5)) // 6 console.log(arr) // [1,2,3,4,5,5]2.arr.pop()从后面删除元素,只能是一个,返回值是删除的元素 let arr [1,2,3,4,5] console.log(arr.pop())//5 …

【Kubernetes 企业项目实战】08、简化 K8s 应用部署工具 Helm V3 入门到企业实战

目录 一、Helm 介绍 1.1 Helm 是什么 1.2 Helm 解决了什么痛点 1.3 Helm 相关组件及概念 1.4 Helm v3 版本变化 1.5 总结 二、安装 Helm 2.1 下载 Helm 2.2 安装 Helm 2.3 配置国内存放 chart 仓库的地址 三、Helm 基本使用 3.1 搜索和下载 Chart 3.2 部署 chart …

Tencent OS下逻辑卷(LVM)创建和扩容

测试环境是一个虚拟机,原配置1个虚拟盘。 创建4个虚拟盘,每盘2G并挂载在虚拟主机上,启动虚拟主机开始测试。 LVM英文是Logical Volume Manager,直接翻译为逻辑卷管理。 这种磁盘管理模式比较灵活,在磁盘空间不足的时…

WSO2通过设定Role来订阅对应的Api

WSO2通过设定Role来订阅对应的Api1. Add Role And User1.0 Add Role1.1 Add User 1.2 Add Mapping2. Upload Api2.1 Upload Three Apis2.2 Inspection3. AwakeningWSO2安装使用的全过程详解: https://blog.csdn.net/weixin_43916074/article/details/127987099. 1. Add Role An…

UnRaid虚拟机安装OpenWrt软路由

文章目录0、前言1、Openwrt虚拟机安装1.1、前提,需要先在UnRaid中开启虚拟机:1.2、下载OpenWrt虚拟机镜像并上传至UnRaid共享文件夹1.3、创建OpenWrt虚拟机2、开启并设置OpenWrt虚拟机2.1、修改OpenWrt管理ip2.2、OpenWrt的上网设置0、前言 最近折腾了很…