B-Tree和B+Tree

本文涉及的产品
PolarClaw,2核4GB
RDS AI 助手,专业版
云数据库 PolarDB MySQL 版,列存表分析加速 4核8GB
简介: 部分内容转载自互联网https://en.wikipedia.org/wiki/B-treehttps://en.wikipedia.org/wiki/B%2B_tree B-Tree 为了描述B-Tree,首先定义一条数据记录为一个二元组[key, data],key为记录的键值,对于不同

部分内容转载自互联网
https://en.wikipedia.org/wiki/B-tree
https://en.wikipedia.org/wiki/B%2B_tree

B-Tree

为了描述B-Tree,首先定义一条数据记录为一个二元组[key, data],key为记录的键值,对于不同数据记录,key是互不相同的;data为数据记录除key外的数据。那么B-Tree是满足下列条件的数据结构:

.1. d为大于1的一个正整数,称为B-Tree的度。

.2. h为一个正整数,称为B-Tree的高度或深度。

.3. 每个非叶子节点由n-1个key和n个指针组成,其中d<=n<=2d。

.4. 每个叶子节点最少包含一个key和两个指针,最多包含2d-1个key和2d个指针,叶节点的指针均为null(因叶子节点是最底层的节点,不需要再指向其他节点) 。

.5. 所有叶节点具有相同的深度,等于树高h。

.6. key和指针互相间隔,节点两端是指针,所以节点中指针比key多一个。

.7. 一个节点中的key从左到右非递减(即升序)排列。

.8. 所有节点组成树结构。

.9. 每个指针要么为null,要么指向另外一个节点。

.10. 如果某个指针在节点node最左边且不为null,则其指向节点的所有key小于v(key1),其中v(key1)为node的第一个key的值。

.11. 如果某个指针在节点node最右边且不为null,则其指向节点的所有key大于v(keym),其中v(keym)为node的最后一个key的值。

.12. 如果某个指针在节点node的左右相邻key分别是keyi和keyi+1且不为null,则其指向节点的所有key小于v(keyi+1)且大于v(keyi)。

图2 是一个d=2的B-Tree示意图。

2

图2

由于B-Tree的特性,在B-Tree中按key检索数据的算法非常直观:
首先从根节点进行二分查找,如果找到则返回对应节点的data,否则对相应区间的指针指向的节点递归进行查找,直到找到节点或找到null指针,前者查找成功,后者查找失败。
B-Tree上查找算法的伪代码如下:

BTree_Search(node, key) {
if(node == null) return null;
foreach(node.key)
{
    if(node.key[i] == key) return node.data[i];
        if(node.key[i] > key) return BTree_Search(point[i]->node);
}
return BTree_Search(point[i+1]->node);
}
data = BTree_Search(root, my_key);

关于B-Tree有一系列有趣的性质,例如一个度为d的B-Tree,设其索引N个key,则其树高h的上限为logd((N+1)/2),检索一个key,其查找节点个数的渐进复杂度为O(logdN)。
从这点可以看出,B-Tree是一个非常有效率的索引数据结构。
另外,由于插入删除新的数据记录会破坏B-Tree的性质,因此在插入删除时,需要对树进行一个分裂、合并、转移等操作以保持B-Tree性质。

B+Tree

B-Tree有许多变种,其中最常见的是B+Tree,例如MySQL就普遍使用B+Tree实现其索引结构。

与B-Tree相比,B+Tree有以下不同点:

.1. 每个节点的指针上限为2d而不是2d+1。(上下矛盾?)

.2. 内节点不存储data,只存储key;叶子节点不存储指针。

图3 是一个简单的B+Tree示意。

3_1_

图3

由于并不是所有节点都具有相同的域,因此B+Tree中叶节点和内节点一般大小不同。
这点与B-Tree不同,虽然B-Tree中不同节点存放的key和指针可能数量不一致,但是每个节点的域和上限是一致的,所以在实现中B-Tree往往对每个节点申请同等大小的空间。

l6UyF
本质差别是B-Tree的每个NODE都记录了data,所以不是每次都要搜叶子节点才能拿到DATA。
B+Tree,只有叶子节点有DATA,因此,每次都要搜到叶子节点取DATA。
但是B+Tree在叶子节点上可以加指向下一个叶子节点的指针,所以范围扫描,B+Tree占优,比如排序。


带有顺序访问指针的B+Tree

一般在数据库系统或文件系统中使用的B+Tree结构都在经典B+Tree的基础上进行了优化,增加了顺序访问指针(称为B* tree)。

4_1_

图4

如图4 所示,在B+Tree的每个叶子节点增加一个指向相邻叶子节点的指针,就形成了带有顺序访问指针的B+Tree。做这个优化的目的是为了提高区间访问的性能,例如图4中如果要查询key为从18到49的所有数据记录,当找到18后,只需顺着节点和指针顺序遍历就可以一次性访问到所有数据节点,极大提到了区间查询效率。

B+树的分裂:当一个结点满时,分配一个新的结点,并将原结点中1/2的数据复制到新结点,最后在父结点中增加新结点的指针;
B+树的分裂只影响原结点和父结点,而不会影响兄弟结点,所以它不需要指向兄弟的指针。

B*树的分裂:当一个结点满时,如果它的下一个兄弟结点未满,那么将一部分数据移到兄弟结点中,再在原结点插入关键字,最后修改父结点中兄弟结点的关键字(因为兄弟结点的关键字范围改变了);
如果兄弟也满了,则在原结点与兄弟结点之间增加新结点,并各复制1/3的数据到新结点,最后在父结点增加新结点的指针。

所以,B*树分配新结点的概率比B+树要低,空间使用率更高;

PostgreSQL B-Tree 索引

也是一种增强版本,具体算法见
src/backend/access/nbtree/README
主要用了两篇论文中的算法,PostgreSQL的插入性能是非常有保障的.

Lehman and Yao's high-concurrency B-tree management algorithm   
(P. Lehman and S. Yao,Efficient Locking for Concurrent Operations on B-Trees, 
ACM Transactions on Database Systems, Vol 6, No. 4, December 1981, pp 650-670).     

a simplified version of the deletion logic described in Lanin and Shasha   
(V. Lanin and D. Shasha, A Symmetric Concurrent B-Tree Algorithm,  
Proceedings of 1986 Fall Joint Computer Conference, pp 380-389).    

Lehman & Yao Algorithm算法优化
添加了一个右指针(like B+Tree),以及一个upper bound value(解决了分裂的并发问题)。

Compared to a classic B-tree, L&Y adds a right-link pointer to each page,
to the page's right sibling.  It also adds a "high key" to each page, which
is an upper bound on the keys that are allowed on that page.  These two
additions make it possible detect a concurrent page split, which allows the
tree to be searched without holding any read locks (except to keep a single
page from being modified while reading it).

When a search follows a downlink to a child page, it compares the page's
high key with the search key.  If the search key is greater than the high
key, the page must've been split concurrently, and you must follow the
right-link to find the new page containing the key range you're looking
for.  This might need to be repeated, if the page has been split more than
once.

MySQL的请参考
http://tech.it168.com/a2011/0711/1216/000001216087_all.shtml

目录
相关文章
|
存储 关系型数据库 数据库
BTree与B+Tree图文详解
B树与B+树区别
2186 0
BTree与B+Tree图文详解
|
监控 Java Linux
JVM调优
JVM调优
812 0
|
存储 关系型数据库 PostgreSQL
深入浅出PostgreSQL B-Tree索引结构
PostgreSQL 的B-Tree索引页分为几种类别 meta page root page # btpo_flags=2 branch page # btpo_flags=0 leaf page # btpo_flags=1 如果即
15338 0
|
6月前
|
XML Java 开发者
springboot自动装配的基本原理
Spring Boot自动装配基于“约定大于配置”理念,通过@SpringBootApplication、@EnableAutoConfiguration与spring.factories机制,结合条件注解实现智能Bean加载。它根据依赖自动配置组件,大幅简化开发。其核心是AutoConfigurationImportSelector筛选符合条件的配置类,实现按需装配。开发者可专注业务,享受“开箱即用”的便捷体验。(238字)
|
8月前
|
人工智能 Java 开发者
【Spring】原理解析:Spring Boot 自动配置
Spring Boot通过“约定优于配置”的设计理念,自动检测项目依赖并根据这些依赖自动装配相应的Bean,从而解放开发者从繁琐的配置工作中解脱出来,专注于业务逻辑实现。
2624 0
|
8月前
|
关系型数据库 MySQL Java
SpringBoot集成Sharding-Jdbc分库分表
ShardingSphere是一套开源分布式数据库中间件解决方案,包含Sharding-JDBC、Sharding-Proxy和Sharding-Sidecar三款产品,提供数据分片、分布式事务和数据库治理功能,适用于多样化应用场景。
1135 0
SpringBoot集成Sharding-Jdbc分库分表
|
缓存 Java 开发工具
Spring是如何解决循环依赖的?从底层源码入手,详细解读Spring框架的三级缓存
三级缓存是Spring框架里,一个经典的技术点,它很好地解决了循环依赖的问题,也是很多面试中会被问到的问题,本文从源码入手,详细剖析Spring三级缓存的来龙去脉。
2235 24
Spring是如何解决循环依赖的?从底层源码入手,详细解读Spring框架的三级缓存
|
存储 数据库 索引
B树与B+树的区别
B树与B+树的区别
|
缓存 JavaScript Java
常见java OOM异常分析排查思路分析
Java虚拟机(JVM)遇到 OutOfMemoryError(OOM)表示内存资源不足。常见OOM情况包括:1) **Java堆空间不足**:内存被大量对象占用且未及时回收,或内存泄漏;解决方法包括调整JVM堆内存大小、优化代码及修复内存泄漏。2) **线程栈空间不足**:单线程栈帧过大或频繁创建线程;可通过优化代码或调整-Xss参数解决。3) **方法区溢出**:运行时生成大量类导致方法区满载;需调整元空间大小或优化类加载机制。4) **本机内存不足**:JNI调用或内存泄漏引起;需检查并优化本机代码。5) **GC造成的内存不足**:频繁GC但效果不佳;需优化JVM参数、代码及垃圾回收器
1195 7
常见java OOM异常分析排查思路分析