Blink Tree 比 B+Tree 性能猛多少???

简介: Blink 树和 B+ 树都是一种类似于B树的数据结构,用于在磁盘上存储和索引数据以实现高效查找和操作。它们的主要区别在于内部节点和叶子节点的结构以及指针的使用方式。总的来说,Blink 树的特点是将内部节点和叶子节点合并为一个节点,减少了树的高度;而 B+ 树通过叶子节点之间的有序链表提高了范围查询和顺序遍历的性能。Blink tree 真的牛啊!# 如果键已经存在,更新值else:# 如果根节点已满,进行分裂else:# 如果是叶子节点,直接插入index = 0index += 1。

 其他系列文章导航

Java基础合集

数据结构与算法合集

设计模式合集

多线程合集

分布式合集

ES合集


文章目录

其他系列文章导航

文章目录

前言

一、B+ tree

1.1 B+ tree 定义

1.2 B+ tree 原理

二、Blink Tree

2.1 Blink Tree 定义

2.2 Blink tree 原理

三、总结


前言

Blink 树和 B+ 树都是一种类似于B树的数据结构,用于在磁盘上存储和索引数据以实现高效查找和操作。它们的主要区别在于内部节点和叶子节点的结构以及指针的使用方式。


一、B+ tree

1.1 B+ tree 定义

B+ 树则是将内部节点和叶子节点分开存储的,内部节点只存储索引键,而叶子节点则存储数据指针。叶子节点之间通过指针连接,形成一个有序链表,这样可以加速范围查询和顺序遍历操作。

1.2 B+ tree 原理

主要是并发场景下,写操作导致节点分裂(SMO,Split Merge Operation)的时候,刚好有并发读操作访问到错误的叶子节点,查错了节点,那么目标值肯定就搜索不到了,于是导致了错误查询。

举个例子:

image.gif编辑

此时,插入一个数据 27,恰好页A满了,需要触发分裂,新增一个页B,且同时有个读取请求,想要访问数据 29。

image.gif编辑

那么很有可能在分裂的时候,读请求访问到老的页面指针,指向了页 A,而页 A 内的 29 已经被分裂到新的页 B 中,这样一来读请求就发现没有 29 ,于是返回没数据,这就错乱了。

而且,叶子节点的分裂,可能会导致父节点的分裂,这种调整最长可能级联到根节点,并发场景下很容易导致错误,为了避免这种情况的发生,最简单的操作就是在发生节点分裂时,把整颗 B+ Tree 都锁了。

这样一来数据的正确性得到了保证,但是性能就很低了,因为全局锁会影响了对所有页的访问。

后续 MySQL 对其在 5.7 版本后做了优化,但是整个 B+Tree 同时只能支持一个 SMO 操作的发生,高并发时大数据量插入导致多 SMO 的发生还是会被阻塞,影响性能。


二、Blink Tree

2.1 Blink Tree 定义

Blink 树是一种新型的数据结构,它将内部节点和叶子节点合并为一个节点,因此在 Blink 树中不存在内部节点和叶子节点的概念。每个节点中存储了索引键和数据指针,这样可以减少内部节点的数量,降低树的高度,从而提高查询性能。

2.2 Blink tree 原理

Blink Tree 主要引入了 high key 和 link 指针来解决并发读写中间态数据访问出错问题,能降低锁的粒度,提高性能。

high key 存储了每个节点的最大值,每个节点的 link 指针则指向了同层右侧的兄弟节点,在写入数据的时候,仅需对当前节点加锁,当前节点修改完毕后立马解锁,锁的粒度很细,并发度很高。

直接来看来阿里云官网给的一个示意图:

image.gif编辑

可以看到,相比于 B+ Tree,Blink Tree 的兄弟节点也进行了指针相连,当分裂在进行中还未完成,也就是父节点到新的子节点的链接还没有建立时,B+ Tree 我们已经演示过了,并发读可能导致数据查询不到。

而 Blink Tree 就能解决这个问题,当读请求沿着老指针访问老页面的时候,对比下 high key,发现查询的值比当前页 high key 大,那么就沿着 link 指针找到旁边新分配的页面,此时就可以找到要查询的值了。


三、总结

总的来说,Blink 树的特点是将内部节点和叶子节点合并为一个节点,减少了树的高度;而 B+ 树通过叶子节点之间的有序链表提高了范围查询和顺序遍历的性能。

Blink tree 真的牛啊!

最后附上简单 B+ tree 的 Python 实现:

class Node:
    def __init__(self, is_leaf=False):
        self.is_leaf = is_leaf
        self.keys = []
        self.children = []
class BPlusTree:
    def __init__(self, degree):
        self.root = Node(is_leaf=True)
        self.degree = degree
    def insert(self, key, value):
        if key in self.root.keys:
            # 如果键已经存在,更新值
            index = self.root.keys.index(key)
            self.root.children[index+1] = value
        else:
            if len(self.root.keys) == (2*self.degree - 1):
                # 如果根节点已满,进行分裂
                new_root = Node()
                new_root.children.append(self.root)
                self.split_child(new_root, 0)
                self._insert_non_full(new_root, key, value)
                self.root = new_root
            else:
                self._insert_non_full(self.root, key, value)
    def _insert_non_full(self, node, key, value):
        if node.is_leaf:
            # 如果是叶子节点,直接插入
            index = 0
            for i in range(len(node.keys)):
                if key > node.keys[i]:
                    index += 1
            node.keys.insert(index, key)
            node.children.insert(index+1, value)
        else:
            # 如果是内部节点,递归插入到子节点
            index = 0
            for i in range(len(node.keys)):
                if key > node.keys[i]:
                    index += 1
            if len(node.children[index].keys) == (2*self.degree - 1):
                self.split_child(node, index)
                if key > node.keys[index]:
                    index += 1
            self._insert_non_full(node.children[index], key, value)
    def split_child(self, parent, index):
        child = parent.children[index]
        new_child = Node(is_leaf=child.is_leaf)
        parent.keys.insert(index, child.keys[self.degree-1])
        parent.children.insert(index+1, new_child)
        new_child.keys = child.keys[self.degree:]
        child.keys = child.keys[:self.degree-1]
        if not child.is_leaf:
            new_child.children = child.children[self.degree:]
            child.children = child.children[:self.degree]
    def search(self, key):
        return self._search(self.root, key)
    def _search(self, node, key):
        index = 0
        for i in range(len(node.keys)):
            if key >= node.keys[i]:
                index = i
        if key == node.keys[index]:
            return node.children[index+1]
        elif node.is_leaf:
            return None
        else:
            return self._search(node.children[index], key)

image.gif

目录
相关文章
|
9月前
|
存储 算法
树(Tree) - 概念与基础
树(Tree) - 概念与基础
169 2
|
3月前
|
前端开发 UED
Tree shaking 技术的原理
【10月更文挑战第14天】tree shaking 技术基于模块系统和静态分析,通过准确识别和移除未使用的代码,实现代码的优化和精简。它是现代前端开发中不可或缺的一部分,有助于提高应用的性能和用户体验。
|
9月前
|
存储 算法 物联网
R-Tree算法:空间索引的高效解决方案
【5月更文挑战第17天】R-Tree是用于多维空间索引的数据结构,常用于地理信息系统、数据库和计算机图形学。它通过分层矩形区域组织数据,支持快速查询。文章介绍了R-Tree的工作原理、应用场景,如地理信息存储和查询,以及Python的`rtree`库实现示例。此外,还讨论了R-Tree的优势(如空间效率和查询性能)与挑战(如实现复杂和内存消耗),以及优化和变种,如R* Tree和STR。R-Tree在机器学习、实时数据分析等领域有广泛应用,并与其他数据结构(如kd-trees和quad-trees)进行比较。未来趋势将聚焦于优化算法、动态适应性和分布式并行计算。
306 1
|
9月前
|
C++
【C++高阶(三)】AVL树深度剖析&模拟实现
【C++高阶(三)】AVL树深度剖析&模拟实现
|
存储 数据库 索引
B-Tree和B+Tree的区别及各自的优势
B-Tree和B+Tree的区别及各自的优势
545 0
|
9月前
|
存储 大数据 OLTP
将LSM-Tree与非易失内存(NVM)相结合的设计与实现
将LSM-Tree与非易失内存(NVM)相结合的设计与实现
124 1
|
9月前
|
存储 设计模式 NoSQL
LSM-Tree - LevelDb 源码解析(一)
LSM-Tree - LevelDb 源码解析(一)
91 0
|
9月前
|
存储 NoSQL Java
LSM-Tree - LevelDb 源码解析(二)
LSM-Tree - LevelDb 源码解析(二)
166 0
|
JSON JavaScript Go
Tree资源树的实战研究
最近小编在做项目的时候,遇到了一个动态添加资源树的问题,经过几番实践,终于实现了最终的结果,下面我会将自己的经历一点点抛给大家,希望读者尽情享受这顿盛宴。
|
9月前
|
算法 关系型数据库 MySQL
长路漫漫, 从Blink-tree 到Bw-tree (上)
在前面的文章 路在脚下, 从BTree 到Polar Index中提到, 我们已经将InnoDB 里面Btree 替换成Blink Tree, 高并发压力下, 在标准的TPCC 场景中最高能够有239%的性能提升, 然后我们对InnoDB 的file space模块也进行了优化, 在分配新pag...
299 0