我知道B-Tree在内存中是如何工作的,它很容易实现.然而,目前我完全无法理解的是如何找到在磁盘上有效工作的数据布局,以便:

  • The number of entries in the B-Tree can grow indefinitly (or at least to > 1000GB)
  • 最大限度地减少了磁盘级拷贝操作
  • 这些值可以有任意大小(即没有固定的模式)

如果有人能提供关于在磁盘级布局B-Tree struct 的见解,我将不胜感激.特别是最后一个要点让我很头疼.我也很欣赏指向书籍的指针,但是我看到的大多数数据库文献只解释了高级 struct (即"这就是您在内存中是如何做的"),但是跳过了关于磁盘布局的细节.

推荐答案

更新(甲骨文索引内部存档版本):http://web.archive.org/web/20161221112438/http://www.toadworld.com/platforms/oracle/w/wiki/11001.oracle-b-tree-index-from-the-concept-to-internals


旧的(原始链接不再存在):

注:

数据库不直接实现基于B-树的索引,而是基于一种称为B+树的变体.根据维基百科的说法:

可以将B+树视为B-树,其中每个 node 只包含关键字(不包含关键字-值对),并且在底部添加了带有链接叶的附加级别.

一般来说,数据库使用面向挡路的存储,并且b+树比b-tree更适合于此.

这些块的大小是固定的,并且留有一些空闲空间来适应将来值或密钥大小的更改.

挡路可以是叶(保存实际数据)或分支(保存指向叶 node 的指针)

如何实现写入磁盘的玩具模型(对于10k大小的挡路,用于简化算术):

  1. 在磁盘上创建一个10G的文件(它有1000个块)
  2. 第一个块被指定为根,下一个空闲块被指定为叶,叶地址列表被放入根中
  3. 插入新数据时,当前叶 node 将填充值,直到达到阈值
  4. 继续插入数据,将下一个空闲数据分配为叶块,并更新叶 node 列表
    1. 经过多次插入,当前根 node 需要子 node ,所以下一个空闲的挡路被分配为分支 node ,从根复制列表,现在根只维护一个中间 node 列表.
    2. 如果需要拆分 node 挡路,则将下一个空闲的挡路分配为分支 node ,添加到根列表中,并在新的分支 node 和初始分支 node 之间拆分叶 node 列表

从大索引中读取信息时:可以执行以下操作:

  1. 首先阅读/根挡路(查找(0),读取(10k)),它指向位于挡路900中的子目录
  2. 阅读挡路900(查找(900*10K),读取(10K)),它指向位于挡路5000中的子元素
  3. 阅读挡路5000(查找(5000*10K),读取(10K)),它指向挡路190中的叶 node
  4. 读取块190(搜索(190*10k),读取(10k))并从中提取感兴趣的值

一个非常大的索引可以拆分到多个文件上,那么挡路的地址将是(文件名_id,地址_相对这个文件)

Database相关问答推荐

位置运算符($)工作不正确

Pocketbase 中的 SQLite 数据库可以根据自己的喜好进行修改吗?

如何高效地存储 100 万个单词并通过starts_with、contains 或ends_with 进行查询?

502 是数据库错误的适当状态代码吗?

如何允许多个用户同时连接到我的 H2 数据库?

The method setListAdapter(ArrayAdapter) is undefined for the type create

是否有任何用于 NoSQL 数据库架构迁移的工具?

触发器、断言和判断之间有什么区别?

如何在数据库中搜索和替换字符串的所有实例?

如何将 SQL Server 数据库图表迁移到另一个数据库?

如何在 liquibase 中标记变更集以进行回滚

有没有一种简单的方法来告诉 alembic 迁移到特定版本?

PostgreSQL 哈希索引

数据库与微服务的一致性

SQL Server Express LocalDB 可以远程连接吗?

如何解析来自 Google 快讯的数据?

如何更正此 sql 连接上的相关名称?

试图在我的环境中设置 Postgres,但似乎无法获得 intidb 的权限

与 IntelliJ IDEA 相比,DataGrip 附加值

Chrome 将其 SQLite 数据库保存到哪里?