图解B+树的生成过程!

本文涉及的产品
RDS MySQL DuckDB 分析主实例,集群系列 4核8GB
RDS AI 助手,专业版
简介: 图解B+树的生成过程!



本文大概字数三千多,预计观看时长十分钟,练习时长两个半小时。希望大家都能学到知识。

前提

不少网友看 B+ 树,看不懂树结构什么意思。希望本文可以帮你理解树结构生成的过程。

在说 B+ 树之前,需要知道,一页的大小是多少。

show global status like 'innodb_page_size'

MySQL一页16kb

这个是看出,一页是 16384 也就是16384/1024 = 16kbinnodb 中一页的大小默认是 16kb。

基于 Spring Boot + MyBatis Plus + Vue & Element 实现的后台管理系统 + 用户小程序,支持 RBAC 动态权限、多租户、数据权限、工作流、三方登录、支付、短信、商城等功能

正文

创建表结构 指定引擎为 Innodb。

CREATE TABLE tree(
    id int PRIMARY key auto_increment,
    t_name VARCHAR(20),
    t_code int 
) ENGINE=INNODB

查看一下当前表的索引情况

show index from tree

B 树和 B+ 树的显示都是 BTREE,但是实际使用的 B+ 树。B+ 树也是 B 树的升级版,这里显示为 B 树也是没有问题的。

BTREE

创建数据,这里会有一个小知识点,如果看过上一篇文章的朋友可以明白是为什么。

INSERT into tree VALUES(3,"变成派大星",3);
INSERT into tree VALUES(1,"变成派大星",1);
INSERT into tree VALUES(2,"变成派大星",2);
INSERT into tree VALUES(4,"变成派大星",4);
INSERT into tree VALUES(7,"变成派大星",7);
INSERT into tree VALUES(5,"变成派大星",5);
INSERT into tree VALUES(6,"变成派大星",6);
INSERT into tree VALUES(8,"变成派大星",8);

插入测试数据

疑问

为什么创建数据的时候数据是乱序的,但是在创建好数据,被排好顺序了。

基础知识

我们在寻找答案之前,想明白一些基础知识。

细心的朋友可以看出来,我们插入 Id 时候数据是乱的,插入进去之后,数据就自动帮我通过 Id 进行排序了,这是为什么呢?接着往下看。

我们如果对于 B+ 树有点了解的话就知道 B+ 树是每页 16KB 进行数据储存。在进行数据查询的时候也是一页一页的去查询。

相当于下面的数据。

首先每一页都有很多数据,就像我们平常去写分页的时候我们返回给前端的数据也会有很多属性。

MySQL数据页

这个可能比较抽象,我是把他当成平常,分页查询的思想代入进去。

我们可以把一页想成是一个对象。

@Data
public class page {
    List<UserRecords> data;
    // ....省略其余属性
}

我们先看一下,一页数据的图是什么样子,仅仅是进行逻辑思考画的图。

这里的 Data,就相当于 一页中的数据区域。

数据区域

但是这里是有限制的,上面我们说到,一页的数据只能是 16Kb,也就是一个 Page 里面的 data 只能16Kb。当数据超过 16Kb,就会新开一个对象相当于在进行创建树的时候增加了判断。

Java 代码思路模拟:

Java模拟MySQL数据页

当 Page 对象的大小已经达到16Kb 就算完成这一页。把这一页放到,磁盘中等待使用就行了,到时候进行查询数据的时候会直接返回这一页,里面包含这些数据。

我们回到最初的问题 为什么我们在进行插入的时候明明 Id 是乱的?等到插入到数据的时候,数据就变成有序的了?我们知道,同时这个数据是根据主键进行排序的,InnoDB 的数据储存一定是要依赖主键的,有些人会想,我就是不创建主键,他还能排序吗?

疑问二

我们在疑问一的基础上,产生出的疑问,不设置主键 Mysql 怎么办?

解答

InnoDB 对聚簇索引处理如下:

  • 如果定义了主键,那么 InnoDB 会使用主键作为聚簇索引
  • 如果没有定义主键,那么会使用第一非空的唯一索引(NOT NULL and UNIQUE INDEX)作为聚簇索引
  • 如果既没有主键也找不到合适的非空索引,InnoDB 会自动帮你创建一个不可见的、长度为 6 字节的 row_id,而且 InnoDB 维护了一个全局的 dictsys.row_id,所以未定义主键的表都共享该row_id,每次插入一条数据,都把全局 row_id 当成主键 id,然后全局 row_id 加 1

很明显,缺少主键的表,InnoDB 会内置一列用于聚簇索引来组织数据。而没有建立主键的话就没法通过主键来进行索引,查询的时候都是全表扫描,小数据量没问题,大数据量就会出现性能问题。

但是,问题真的只是查询影响吗?不是的,对于生成的 ROW_ID,其自增的实现来源于一个全局的序列,而所以有 ROW_ID 的表共享该序列,这也意味着插入的时候生成需要共享一个序列,那么高并发插入的时候为了保持唯一性就避免不了锁的竞争,进而影响性能

解答

我们看完疑问二的解答就知道,即便我们不设置主键。数据也会帮我们去生成一个默认的主键,有点像,类默认生成构造器的思想。

有了主键之后呢?

表中有主键

为什么会自动排序,大家都知道了。其实在文章之初就会有很多人明白是为什么,大概脑子里会有答案。

疑问三

为什么要进行排序?

解答

我们都知道,在进行数据查找的时候,比如几个基础的查找算法的,前提都是,先进行排序。再者 List 和 Map 的一些区别肯定都很熟悉了。排序当然是为了更快,所以无须的 Id 会对插入效率造成影响,也就是为什么很多文章说使用自增 Id 比 UUID 或者雪花算效率高的原因。第一个是 UUID 他们是随机的 每次都要重新排序,甚至可能会因为排序的原因造成页数据的更换。还有就是 UUID 一般都比较长,一页是 16Kb 数据越短。一页的数据就会越多,查询的速度也就比较快。

这里说完为什么排序 还有一个点就是上面的「页目录」

疑问三

页目录的作用是什么?

页目录的作用是减少范围。

页目录

这里的第三层是数据,上面都是目录,可以增加数据的检索效率。

页目录增加数据的检索效率

如果没有目录我们需要去直接遍历数据区域,会降低效率。目录能帮我们缩小范围,这里,我们查询 ID = 3。我们可以通过目录知道 1 < 3 < 4,如果在 1 中没有找到对应数据。但是因为 3 < 4 就不会接着往下查询了,直接返回空结果。

当第一页没有的时候去第二页查询,不会直接跳到第二页查询。

提高范围查找效率

为了提高效率,当目录数据数量过多时,就会网上延伸一层树,同时可以减少磁盘的 IO 次数。

索引就是一颗树

关于所有叶子节点都处于同一深度是如何实现的?这与 B+ 树具体的插入和删除算法有关。简单解释一下插入时的情况,根据插入值的大小,逐步向下直到对应的叶子节点。如果叶子节点关键字个数小于 2t,则直接插入值或者更新卫星数据;如果插入之前叶子节点已经满了,则分裂该叶子节点成两半,并把中间值提上到父节点的关键字中,如果这导致父节点满了的话,则把该父节点分裂,如此递归向上。所以树高是一层层的增加的,叶子节点永远都在同一深度。

基于 Spring Cloud Alibaba + Gateway + Nacos + RocketMQ + Vue & Element 实现的后台管理系统 + 用户小程序,支持 RBAC 动态权限、多租户、数据权限、工作流、三方登录、支付、短信、商城等功能

小总结

  • 内部节点并不存储真正的信息,而是保存其叶子节点的最小值作为索引。
  • 每次插入删除都进行更新(此时用到parent指针),保持最新状态。
  • B+ 树非叶子节点上是不存储数据的,仅存储键值
  • B+ 树只在叶子节点上储存“数据”,上层就会存储更多的键值,相应的树的阶数(节点的子节点树)就会更大,树就会更矮更胖,如此一来我们查找数据进行磁盘的 IO 次数又会再次减少,数据查询的效率也会更快。
  • B+ 树的阶数是等于键值的数量的,如果我们的 B+ 树一个节点可以存储 1000 个键值,那么 3 层 B+ 树可以存储 1000×1000×1000=10 亿个数据。
  • 一般根节点是常驻内存的,所以一般我们查找 10 亿数据,只需要 2 次磁盘 IO。
  • 因为 B+ 树索引的所有“数据”均存储在叶子节点,而且数据是按照顺序排列的。
  • 那么 B+ 树使得范围查找,排序查找,分组查找以及去重查找变得异常简单
  • 有心的读者可能还发现上图 B+ 树中各个页之间是通过双向链表连接的,叶子节点中的数据是通过单向链表连接的。
  • 其实上面的 B 树我们也可以对各个节点加上链表。这些不是它们之前的区别,是因为在 MySQL 的 InnoDB 存储引擎中,索引就是这样存储的。
  • 我们通过数据页之间通过双向链表连接以及叶子节点中数据之间通过单向链表连接的方式可以找到表中所有的数据。

结尾

感觉写的有点啰嗦了 但是还是有点加深印象的 后续会接着整理一下相关的资料 补充进来

  • 如果你是直接跳到这里,看看文章有多长 建议收藏
  • 如果你一步步看到这里,感觉有点帮助 赞赞来一个
  • 如果感觉文章有问题,建议评论区指出 会修正

文章完结🥰



相关实践学习
每个IT人都想学的“Web应用上云经典架构”实战
本实验从Web应用上云这个最基本的、最普遍的需求出发,帮助IT从业者们通过“阿里云Web应用上云解决方案”,了解一个企业级Web应用上云的常见架构,了解如何构建一个高可用、可扩展的企业级应用架构。
MySQL数据库入门学习
本课程通过最流行的开源数据库MySQL带你了解数据库的世界。 &nbsp; 相关的阿里云产品:云数据库RDS MySQL 版 阿里云关系型数据库RDS(Relational Database Service)是一种稳定可靠、可弹性伸缩的在线数据库服务,提供容灾、备份、恢复、迁移等方面的全套解决方案,彻底解决数据库运维的烦恼。 了解产品详情:&nbsp;https://www.aliyun.com/product/rds/mysql&nbsp;
相关文章
|
5月前
|
编解码 数据处理 API
如何用阿里云OSS对图片和视频进行数据处理?
本文介绍了如何利用阿里云对象存储OSS进行图片和视频处理。OSS提供了丰富的功能,如图片的缩放、裁剪、旋转和水印添加等,用户只需在图片URL后附加处理参数即可实现自动化处理。同时,OSS还支持自定义样式模板,便于批量操作。对于视频处理,OSS支持转码、截图、拼接等功能,满足多终端播放需求。通过OSS的API和SDK,开发者可以方便地集成这些功能,提升数据管理效率。
|
机器学习/深度学习 人工智能 安全
基于YOLOv8的路面缺陷(路面裂缝、井盖、坑洼路面)识别项目【完整源码数据集+PyQt5界面+完整训练流程+开箱即用!】
本项目基于YOLOv8与PyQt5,打造路面缺陷检测系统,支持裂缝、井盖、坑洼识别,涵盖图片、视频、摄像头等多种输入方式。提供完整训练数据、预训练模型及图形化界面,开箱即用,本地运行,方便二次开发。适用于智慧城市建设与道路安全巡检,推动AI检测技术实际应用。项目包含源码、数据集、训练代码,支持科研学习与工程实战。
|
11月前
|
存储 前端开发 数据可视化
Grafana Loki,轻量级日志系统
本文介绍了基于Grafana、Loki和Alloy构建的轻量级日志系统。Loki是一个由Grafana Labs开发的日志聚合系统,具备高可用性和多租户支持,专注于日志而非指标,通过标签索引而非内容索引实现高效存储。Alloy则是用于收集和转发日志至Loki的强大工具。文章详细描述了系统的架构、组件及其工作流程,并提供了快速搭建指南,包括准备步骤、部署命令及验证方法。此外,还展示了如何使用Grafana查看日志,以及一些基本的LogQL查询示例。最后,作者探讨了Loki架构的独特之处,提出了“巨型单体模块化”的概念,即一个应用既可单体部署也可分布式部署,整体协同实现全部功能。
4282 69
Grafana Loki,轻量级日志系统
|
消息中间件 存储 算法
时间轮在Kafka的实践:技术深度剖析
【8月更文挑战第13天】在分布式消息系统Kafka中,时间轮(Timing Wheel)作为一种高效的时间调度机制,被广泛应用于处理各种延时操作,如延时生产、延时拉取和延时删除等。本文将深入探讨时间轮在Kafka中的实践应用,解析其技术原理、优势及具体实现方式。
479 2
|
XML Java 数据格式
Spring IOC—基于XML配置Bean的更多内容和细节(通俗易懂)
Spring 第二节内容补充 关于Bean配置的更多内容和细节 万字详解!
757 18
Spring IOC—基于XML配置Bean的更多内容和细节(通俗易懂)
|
Java BI 调度
SpringBoot整合XXLJob
XXLJob是一个分布式任务调度平台,优点:开发迅速、学习简单、轻量级、易扩展。是大众点评员工xxl创建并维护,基于 GPL-3.0 开源,可放心商用,目前已经拥有庞大的使用群体。 简单来说,就是一个定时任务中间件,类似的产品有当当网开源的Elastic-Job。
2205 111
SpringBoot整合XXLJob
|
Python
【Python-numpy】numpy.random.choice()解析与使用
本文介绍了NumPy中的`numpy.random.choice()`函数,它用于从一维数组或整数范围内根据指定概率或均匀分布生成随机样本,支持设置样本大小、是否替换以及每个元素的特定概率。
661 5
|
存储
数据结构(8)树形结构——B树、B+树(含完整建树过程)
8.1.B树 8.1.1.概述 B树存在的意义: 二叉树在存储数据时可能出现向一边倾斜导致查询效率降低的情况,为了防止二叉树的倾斜,出现了平衡二叉树,通过旋转的方式保证二叉树的平衡。但是就算是保持绝对的平衡,在面对要存储的数量量级够大的时候也会出现树的高度整体偏高的问题,树的高度过高,即使是使用了二分查找,依然会出现查找效率变低的情况。尤其是磁盘查找数据本身是个机械完成的动作,这一动作本身就十分耗时。因此需要一种能进行二分查找缩短查找时间,能存储大量数据后树高也不会过高的树形结构,这就是B树。
1157 0

热门文章

最新文章