tree mysql_B+Tree 介绍与在 Mysql 中的应用

1、B树简绍

B 树又称平衡多路查找树。

1.1、用阶来描述 B 树

一个 m 阶的 B 树具有一下特点:

1 每个结点最多包含 m 个子节点;

2 除根节点外,每个分支结点至少有 ceil(m/2) 个子节点;

3 根结点若非叶子结点,则至少 2 个子节点;

4 所有叶子结点都出现在同一层;

5 有 n 个子结点的非叶子结点恰好有 n - 1 个关键字,关键字按递增顺序排序。

1.2、用图片描述 B 树

下图是一个 4 阶的 B 树

000da6f11629

4 阶 B 树

下图是一个 3 阶的 B 树

000da6f11629

3 阶 B 树

1.3、用代码描述 B 树

#define m 1024

struct BTNode;

typedef struct BTNode * PBTNode;

struct BTNode {

int keyNum; // 实际关键字个数,key < m

PBTNode parent; // 指向父节点

PBTNode *ptr; // 子树指向向量:ptr[0]...ptr[keyNum]

KeyType *key; // 关键字向量:key[0]...key[keyNum-1]

};

typedef struct BTNode * BTree;

typedef struct BTree * PBTree

2、B+ 树介绍

B+ 树是 B 树的变形。一棵 m 阶 B+ 树和 m 阶 B 树的异同点如下:

1 有 n 个子结点的 B+ 树有 n 个关键字,而 B 树则是有 n -1 个关键字;

2 B+ 树的内结点不存储 data ,只存储 key;

3 B+ 树的所有叶子结点中包含所有信息,叶子结点本身依关键字大小依次顺序链接;

4 B+ 树所有的非终端结点可以看成是索引部分,结点中仅含有其子结点的最大(或最小)关键字。

2.1、用图片描述 B+ 树

下图是一个三阶的 B+ 树

000da6f11629

三阶 B+ 树

000da6f11629

三阶 B+ 树

3、B+树查找过程及其效率

上图中,假设需要查询 key 为 80 的数据,首先需要将根结点加载,通过比较,80 大于 65,则会通过 P3 指针再加载对应的结点,在将结点上的 key 与 80 比较,最后定位在 P2 指针对应的区域在进行加载获取数据。

上述查找过程,一共进行了 3 次加载过程,加载次数本质上 B+ 树的树高。实际上,B+ 树的查找效率取决于树高 h。

假设当前数据表的数据量为 N,每个结点的关键字数量是 m,则树高 :

000da6f11629

树高公式

在根据对数函数的函数特性:

000da6f11629

对数函数

当数据量 N 情况一定的情况下,m 越大,h 越小。数据库系统的设计者巧妙利用了磁盘预读原理,将一个节点的大小设为等于一个页,这样每个节点只需要一次I/O就可以完全载入。而 m = 磁盘块大小/数据项大小,磁盘块的大小就是数据页的大小,是固定的,一般是 4k。

从上可以看出,要提高 B+ 树的查询效率,就需要降低树高,要降低树高,数据库系统就要求数据项的大小尽量小。Mysql 就采用 B+ 树作为索引文件,索引字段的大小与数据项的大小成正比,因此在数据库查询调优中,就有要求索引字段尽量小。短小的索引字段,能够有效的降低树高,提高查询效率。

4、B+ 树结点数据的插入

B+ 树大致的插入算法如下:

1)寻找需要插入数据的目标叶节点;

2)判断插入的数据是否比 B+ 树目前最小值还小,如果是更新全树非叶结点的最小值;

3)判断目标叶结点是否数据满,未满的情况下直接插入数据;

4)在叶结点已经满的情况下,分裂叶结点,将包括待插入数据在内的数据均分成两个新结点;

5)在分裂的情况下,将新的结点在父节点未出现的最小值插入父节点;

6)父节点重复插入数据的过程,直到没有新结点需要分裂的情况;

7)如果是根结点需要分裂,将它视为有一个空的父节点,重复上述插入数据的过程。

下面以具体的数据演示插入数据的过程

000da6f11629

三阶 B+ 树

插入数据 7,更新所有所有非叶结点最小值,然后插入 7

000da6f11629

更新最小值

000da6f11629

插入数据 7

插入数据 6,更新所有非叶节点最小值,然后拆分叶结点

000da6f11629

更新最小值

000da6f11629

插入数据待拆分

拆分结点,将两个结点中未在父节点出现的最小值插入父结点

000da6f11629

拆分结点

000da6f11629

拆分父节点

将拆分的新结点中未在父节点(空结点)出现的最小值插入父节点

000da6f11629

更新根结点

当然,为了减少结点的拆分,提高磁盘利用率,减少磁盘 I/O 次数,B+ 树的插入还提供了旋转功能。当叶结点已满但其左右兄弟节点没有满的情况下,B+ 树并不急于去做拆分操作,而是将记录移到当前所在页的兄弟节点上。通常情况下,左兄弟会被先检查用来做旋转操作。

例如如下情况,在插入 85 的情况下可以进行左旋操作

000da6f11629

左旋示例 B+ 树

000da6f11629

插入85

000da6f11629

左旋操作

4、B+ 树在 Mysql 中的应用

在 Mysql 中,索引是采用 B+ 树的结构进行组织,从而形成索引文件。索引是属于存储引擎级别的概念,下面主要介绍 MyISAM 和 InnoDB 两个存储引擎的索引实现方式。

4.1、非聚集索引存储引擎 MyISAM

此处借用他人的图片进行说明,MyISAM 存储引擎在 B+ 树的叶结点,存放的是数据记录的地址。下面两种张图分别展示了主键与辅助索引的 B+ 树的结构。

000da6f11629

主键 B+ 树

000da6f11629

辅助索引 B+ 树

所谓的聚集非聚集是针对叶结点的 data 中是否存储有完整的数据记录来区分的,MyISAM 中 data 只存储数据记录的地址,因而是非聚集索引。

4.2、聚集索引存储引擎 InnoDB

此处同样借用他人的图片进行说明。

000da6f11629

主键索引

000da6f11629

辅助索引

从上图可以看出,InnoDB 的所有辅助索引都引用主键作为 data 域。聚集索引使得在利用主键进行查询时,搜索十分高效,而利用辅助索引进行查询是,需要检索两遍索引。

知道InnoDB的索引实现后,就很容易明白为什么不建议使用过长的字段作为主键,因为所有辅助索引都引用主索引,过长的主索引会令辅助索引变得过大。再例如,用非单调的字段作为主键在InnoDB中不是个好主意,因为InnoDB数据文件本身是一颗B+Tree,非单调的主键会造成在插入新记录时数据文件为了维持B+Tree的特性而频繁的分裂调整,十分低效,而使用自增字段作为主键则是一个很好的选择。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值