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 树

4 阶 B 树

下图是一个 3 阶的 B 树
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+ 树


三阶 B+ 树
三阶 B+ 树

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

上图中,假设需要查询 key 为 80 的数据,首先需要将根结点加载,通过比较,80 大于 65,则会通过 P3 指针再加载对应的结点,在将结点上的 key 与 80 比较,最后定位在 P2 指针对应的区域在进行加载获取数据。
上述查找过程,一共进行了 3 次加载过程,加载次数本质上 B+ 树的树高。实际上,B+ 树的查找效率取决于树高 h。
假设当前数据表的数据量为 N,每个结点的关键字数量是 m,则树高 :


树高公式

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


对数函数

当数据量 N 情况一定的情况下,m 越大,h 越小。数据库系统的设计者巧妙利用了磁盘预读原理,将一个节点的大小设为等于一个页,这样每个节点只需要一次I/O就可以完全载入。而 m = 磁盘块大小/数据项大小,磁盘块的大小就是数据页的大小,是固定的,一般是 4k。
从上可以看出,要提高 B+ 树的查询效率,就需要降低树高,要降低树高,数据库系统就要求数据项的大小尽量小。Mysql 就采用 B+ 树作为索引文件,索引字段的大小与数据项的大小成正比,因此在数据库查询调优中,就有要求索引字段尽量小。短小的索引字段,能够有效的降低树高,提高查询效率。

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

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

1)寻找需要插入数据的目标叶节点;
2)判断插入的数据是否比 B+ 树目前最小值还小,如果是更新全树非叶结点的最小值;
3)判断目标叶结点是否数据满,未满的情况下直接插入数据;
4)在叶结点已经满的情况下,分裂叶结点,将包括待插入数据在内的数据均分成两个新结点;
5)在分裂的情况下,将新的结点在父节点未出现的最小值插入父节点;
6)父节点重复插入数据的过程,直到没有新结点需要分裂的情况;
7)如果是根结点需要分裂,将它视为有一个空的父节点,重复上述插入数据的过程。

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


三阶 B+ 树

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


更新最小值
插入数据 7

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


更新最小值
插入数据待拆分

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


拆分结点
拆分父节点

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


更新根结点

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


左旋示例 B+ 树
插入85
左旋操作

4、B+ 树在 Mysql 中的应用

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

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

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


主键 B+ 树
辅助索引 B+ 树

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

4.2、聚集索引存储引擎 InnoDB

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


主键索引
辅助索引

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


转载整理自
[1]: 万字总结:学习MySQL优化原理,这一篇就够了!
[2]: MySQL 索引及查询优化总结
[3]: B+ tree
[4]: B+树的几点总结
[5]: 图解B+树的插入和删除
[6]: MYSQL-B+TREE索引原理
[7]: 从B树、B+树、B*树谈到R 树
[8]: 从MySQL Bug#67718浅谈B+树索引的分裂优化

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 204,053评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,527评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,779评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,685评论 1 276
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,699评论 5 366
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,609评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,989评论 3 396
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,654评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,890评论 1 298
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,634评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,716评论 1 330
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,394评论 4 319
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,976评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,950评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,191评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 44,849评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,458评论 2 342