文章详情

短信预约-IT技能 免费直播动态提醒

请输入下面的图形验证码

提交验证

短信预约提醒成功

CMU 15445 学习之Tree Index I

2024-12-01 12:56

关注

表索引(Index)指的是表中数据的一些子集,这些子集能够标识表中数据的一些特征,以便能够快速的去查找 table 中的数据,并且数据库能够保证,表中数据和表索引数据的一致性。

B+ Tree 基本概念

B+ Tree 实际上是一种平衡树结构,它能够保证数据有序存储,可以在平均 O(log n) 复杂度下查询、插入、删除数据。

它实际上类似二叉平衡树,但是每个节点可以拥有不止 2 个子节点,并且能够适配数据库需要读取整块数据的需求,提升数据读写的效率。

B+ 树是一个多叉平衡树,例如 M 个分叉指的是每个 inner node 都有 M 个路径到子节点,具有以下基本特征:

下图所示,是一个 B+ Tree 的例子。

最底层的节点叫做 leaf node 叶子节点,上层的叫做 inner node,最顶层的 inner node 就是根节点(root node)。

inner node 中不会存储实际的数据,而是存储 key 以及指向其子节点的指针。

叶子节点之间有指针串联,方便进行 scan 操作;每个叶子节点中存储了实际的 key/value 数据。

叶子节点的内部结构,一般有两种不同的布局方式,一种是很常见的,存储一个 page id,并且将索引的 key 和 value 都存放到节点中,然后一个 page 指向下一个 page。

这样是将 key/value 保存在了一起,并不利于顺序扫描,如果我们只需要扫描 key 的话,那么会有一些额外的消耗。

另一种方式是将 key 和 value 分开,结构大致如下所示:

其中包含了一些元数据信息,例如当前的层数,空闲空间等,以及一个有序的 key 列表,并且每一个 key 指向了它自己的 value。

而实际 value 所表示的数据,各个系统有不同的实现,大致有两种:一是存储一个记录 id,指向磁盘的 page 中数据的实际位置;二是直接就存储数据本身。

B+ Tree 操作

insert

B+ 树中插入操作大致流程如下:

重新分布该叶子节点上的数据,以最中间的 key 为界,右边的数据分裂到新的节点中

分裂的时候,需要将叶子节点中间的 key 推送到上层父节点

如果上层父节点又需要分裂,则重复执行上述过程

delete

delete 操作大致是和 insert 相反的,插入的时候,如果一个节点上的数据满了,则需要分裂;而删除时,如果一个节点中的数据少于了 M/2-1,则破坏了 B+ Tree 的定义,这时候需要将节点进行合并,称为 merge。

大致过程如下:

尝试重分布,如果邻近节点有富余,则从邻近的节点中拿一个 key

如果邻近节点也没有多余的数据,则尝试和兄弟节点合并

这里有一个网站,动态展示了 B+ 树的插入、删除、查找过程,能够更好帮你理解 B+ 树。https://www.cs.usfca.edu/~galles/visualization/BPlusTree.html

B+ Tree Design

接下来在简要分析下关于 B+ Tree 的一些设计问题。

Node Size

对于 B+ 树中每个节点的大小,这其实并不确定,或者说依赖于硬件环境和数据库类型,sql 查询类型等因素。

大致来说,存储介质速度越慢,则一个节点的容量就越大,道理也很简单。当在慢速的介质中,例如磁盘,我么肯定希望能够一次性多读取一部分数据到内存中,尽量避免多次随机 IO。在越快速的设备上,则节点的容量越小。

可以参考内存中的 cache line 和操作系统维护的 page size。MySQL 的 B+ 树节点大小一般是 16KB。

Merge Threshold

前面说到了删除数据时可能会触发 B+ 树的 merge 节点操作,但是在实际的实现中,一些数据库系统并不是只要满足条件就会马上执行,而是累积到一段时间之后,再进行 merge。

因为 merge 是一个很“昂贵”的操作,涉及到磁盘上的数据调整分布,一些系统中会有一些后台进程,定期去触发这个操作。

Variable-Length Keys

前面提到的 B+ Tree 中存储的都是固定 size 的 key,但是实际环境中,我们的 key 或者 value 都有可能是不定长的。针对不定长的 key,一般有这几种解决办法:

1.节点中不存储实际的 key,而是存储指向实际 tuple 属性的指针,这样的话虽然能够固定大小,但是指针并没有 key 本身具有的特征,范围扫描低效,实际使用并不多。

2.节点的 size 也不固定,来适配不同长度的 key

3.对齐,总是将 key 对齐为其类型的大小,而不管 key 的 size 有多大。这种方式缺点也显而易见,就是可能会浪费一定的空间。

4.使用类似 slot page 的组织方式,将 key 存在一个有序的集合中,并且指向其实际的数据。

Non-Unique Index

数据库中的索引,有时候可以存在重复的数据,除了唯一索引外。因此,在 B+ Tree 存储数据的时候,需要对重复的 key 进行处理。

Duplicate Keys

存储重复 key 很好理解,就是我们可以把重复的 key 也当做是一个单独的 key 进行存储即可。

Va

lue List

value list 就是对重复 key 的 value 维护了一个链表,将其串联起来。

B+ Tree Optimizations

最后再来看下关于 B+ 树在设计时的一些优化方案。

Prefix Compression

因为 B+ 树底层叶子节点的数据是有序排列的,因此存储在同一个叶子节点的数据,有很大可能是具有相同的特征的,例如可能是类似的,拥有相同的前缀。

所以,针对那些有相同前缀的数据,可以只存储一份前缀数据,而不用每个 key 都单独存储一份。

Suffix Truncation

前面提到过 B+ 树中 inner node 只存储了 key 和索引信息,并不存储数据,只是做为一个辅助查找的索引节点。因此 inner node 中的 key 并不用是完整的 key,只要能够起到区分查找的作用就可以了。

例如上面的例子,由于这两个 key 所有字符都不一致,因此并不需要存储完整的 key,只需要存储能够帮助查找到下一级节点的信息就可以了。

Bulk Insert

最好的构建 B+ 树的方式,是将一组有序的数据从下到上构建 B+ 树的多级索引,这样不会存在 B+ 树的分裂或者合并,效率是最高的。

因此如果有一部分初始化数据需要插入到 B+ 树中,可以先将其排序,然后直接构建 B+ 树。

Pointer Swizzling

B+ 树遍历 page 的时候,每次都需要从 buffer pool 中获取 page 的位置信息,然后 B+ 树根据这个位置去获取 Buffer Pool 中的 page 数据。

例如上图中,需要获取 page id 为 2 的 page,则会先从 page table 中获取,Buffer Pool 判断这个 page 是否在内存中,如果不在则加载这个 page 到内存,并且返回一个 page 的指针(page 的实际位置)给 B+ 树。

如果 B+ 树确认扫描到的 page 肯定在内存中,那么可以直接存储 page 指针,省去了从 page table 中寻址的开销。

这个优化比较适用于 B+ 树的上层节点,因为 B+ 树上面的几层节点容量相对较小,并且会被频繁的访问到,可以缓存到内存中加速 B+ 树的查询。

Conclusion

这一节讲述了 B+ 树的一些基本概念,相信读者能够对其有一个基本的理解了,在大多数情况下,B+ 树是一个在数据库中应用非常广泛的结构。

来源:roseduan写字的地方内容投诉

免责声明:

① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。

② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341

软考中级精品资料免费领

  • 历年真题答案解析
  • 备考技巧名师总结
  • 高频考点精准押题
  • 2024年上半年信息系统项目管理师第二批次真题及答案解析(完整版)

    难度     813人已做
    查看
  • 【考后总结】2024年5月26日信息系统项目管理师第2批次考情分析

    难度     354人已做
    查看
  • 【考后总结】2024年5月25日信息系统项目管理师第1批次考情分析

    难度     318人已做
    查看
  • 2024年上半年软考高项第一、二批次真题考点汇总(完整版)

    难度     435人已做
    查看
  • 2024年上半年系统架构设计师考试综合知识真题

    难度     224人已做
    查看

相关文章

发现更多好内容

猜你喜欢

AI推送时光机
位置:首页-资讯-后端开发
咦!没有更多了?去看看其它编程学习网 内容吧
首页课程
资料下载
问答资讯