IT 人转技术管理:B+树从小到大的演变过程详细讲解

我整理了一些关于【IT人到技术管理】的项目学习资料(内附讲解~~)分享给大家学习:

我们已经知道B+树的组织结构以及不同层之间的关系。

现在我们来模拟一下B+树从小到大,从无到有,从简单到复杂的生长过程。

首先让我们做一些假设:

1.每个页面(包括内部节点和叶子节点)最多可以插入三条记录,当插入第四条记录时,会引起分裂。

2.插入的数据是键值对,但是我们只关心键,不需要关心值,所以可以简单的表示为数据。

3.插入的数据顺序为:10,20,5,8,23,22,50,21,53,40,9

4.为了简单起见,密钥是一些简单的int类型数字

5.假设根节点的页码为100

第一次插入过程。此时索引中还没有数据,所以B+树的根节点为空。

因为页面只能存储三个键,所以先将 10、20、5 插入其中,然后在页面内对数据库进行排序,并对这三个键进行索引。 之后的 B+ 树应该如下图所示。

mysql运维 mysql运维内参_子节点

按照假设,根页面已经完全插入,但是还有更多的数据需要插入,如果继续插入,则需要对根叶子进行分裂,分类过程如下:

1.首先创建新的叶子节点,假设请求的页面为101。在分裂过程中,根节点永远不会改变,无论树变得多大,根节点的页面始终保持不变。

2.然后将根节点的所有记录复制到新的页面中,原根页面的最小记录指向新的叶子节点,并删除根页面的所有记录。

3.最后将根页面的min指针指向新的叶子节点页面101。

这样改造之后,新的B+树结构如下图所示。

mysql运维 mysql运维内参_子节点_02

至此,根节点的分类已经完成,但是我们要插入的key--8还没有插入,所以需要继续插入。

当插入8的时候,可以想到直接通过定位找到101页,当在这个页面插入的时候发现还是没有空间,此时这个页面是属于一个叶子节点的,所以就存在叶子节点的分裂。

步骤如下:

1.首先创建叶子节点,假设页码不为102

2. 将第 101 页上的一半数据迁移到第 102 页。这里我们可以假设每次迁移一个条目。

3、第101页和第102页都是叶子节点,一般称之为兄弟关系,需要组成双向链表。

4. 将一半数据迁移到页面 102 后,页面 102 只剩下一条 key 为 20 的记录。注意页面 102 也是叶子节点,所以这个页面也需要和根节点关联起来。需要做的就是提取出记录 20 的 key。

然后添加一个指针信息,也就是这里的页面102,形成一条新的记录,插入到根页面中,然后这条记录指向对应的子节点页面102。

这样就完成了叶子节点的分裂,重新调整了B+树,如下图所示:

mysql运维 mysql运维内参_子节点_03

拆分到此处后,插入键 (8) 非常简单。

从根页面开始查找,由于8小于20,我们还是按照最小记录数查找对应的叶子节点,结果找到了101页,然后在这个页面上插入数据,此时插入条件满足。

使用同样的方法,我们从根节点开始搜索,轻松插入两个记录:key(23),key(22)。此时的B+如下图所示:

mysql运维 mysql运维内参_搜索_04

现在我们继续插入 key(50) 的行,因为大于 20,索引找到 102 子页,但是 102 页已经满了,所以继续进行拆分。这个分类依然是叶子节点的拆分。

同样的,先申请一个叶子节点页面,假设页码为页面103。然后将页面102上的一半数据键(23)移动到页面103,进而建立页面103和根页面的父子关系。

这样就创建了一个新的叶节点,即第 103 页。第 103 页也是第 102 页的兄弟节点,需要使用双向链表连接。

经过这样的改造之后,新的B+树结构如下:

mysql运维 mysql运维内参_搜索_05

分裂之后,用同样的方法从根节点开始搜索,轻松插入三行数据:key(50),key(21),key(53)。

然后当我们继续插入键(40)时,由于它大于键(23),所以应该将其插入到第 103 页。但是,第 103 页已经满了,因此叶子节点再次被分裂。

假设本次请求的页面为第104页,分裂并插入键(40)后的B+树如下:

mysql运维 mysql运维内参_数据_06

继续插入下一个数据键(9)。在根页中,因为键(9)小于键(20),所以我们应该找到页面 101 来插入数据,但是该页面已满,需要再次拆分。

类似地,创建一个新的叶子节点page,并将页码设置为105。移动数据,使之成为page 101的兄弟节点。

一切完成后,以105页(从101页搬过来的)上的唯一键(10)与根节点建立父子关系,建立新的索引记录(Key:10,Pageno:105),并将其插入到根节点页面中。

此时发现根页面已经满了,明显需要进行根页面分裂。

我们先来看一下当前的B+树(其实还不能称之为完整的B+树),如下所示:

mysql运维 mysql运维内参_子节点_07

可见105页没有父亲,需要通过分裂给他找一个父亲。

新请求的页面应该是内节点页面,因为它是用来存储索引而不是叶子页面数据的。假设这个页面是第 106 页。

这里要注意的是,由于根节点始终是根节点,所以根节点上的所有数据还是需要移动到106页,相当于101到105这五个页面的父节点变成了106页,100页的最小节点也会指向106页。

此时B+树已经有三层结构了,如下图所示:

mysql运维 mysql运维内参_搜索_08

此时节点 105 仍然无法将索引信息写入父节点,因为节点 106 仍为满。因此继续分裂。

表示本次的分裂不是页面节点或者根节点的分裂,而是内部节点的分裂。

内部节点的分裂方式和叶子节点类似,依然是申请一个新的节点,假设是页面107,然后让它成为页面106的兄弟页面,将一条数据移动到页面107之后,再将索引记录(key: 53, pageno: 107)插入到根页面中。

此时新的B+树结构如下图所示:

mysql运维 mysql运维内参_数据_09

此时继续在106页插入索引数据(key:10,pageno:105)。此时经过两次split之后,

此时,第 106 页包含三条键为(10、20、23)的记录,分别指向第 105、102 和 103 页。

最后,节点105也找到了自己的父节点,此时的B+树如下图所示:

mysql运维 mysql运维内参_MySQL运维内参_10

等等,别忘了业务,我们的数据插入任务还没有完成。

插入数据键(9)。从根目录搜索,我们仍然会找到第 101 页,现在我们可以将数据直接写入第 101 页。

所有数据插入后的完整B+树如下图所示:

mysql运维 mysql运维内参_搜索_11

此时我们回头看一下需要插入的数据顺序是:10,20,5,23,22,50,21,53,40,9。

此时可以看最后一张图的叶子节点,从左到右读取所有记录,顺序为:5,8,9,10,20,21,22,23,40,50,53。

显然这相当于对原始序列进行排序,并包含所有数据。

如果要查询整张表的话,InnoDB会直接找到最左边的叶子节点,然后从左到右读取所有的数据,这就是我们介绍过的B+树的特性。

整理了一些【IT人到技术管理】的项目学习资料(附讲解~~),需要的可以收藏一下:

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值