【问题标题】:Why B-Tree for file systems?为什么选择文件系统的 B-Tree?
【发布时间】:2015-09-10 22:36:37
【问题描述】:

我知道这是一个常见问题,我在 Stack Overflow 中看到了一些线程,但仍然无法理解。

这里是堆栈溢出的公认答案:

" 磁盘寻道成本很高。B-Tree 结构专门设计用于 尽可能避免磁盘寻道。因此 B-Tree 包含更多 键/指针指向单个节点,而不是二叉树。这个性质 使树非常平坦。通常大多数 B 树只有 3 或 4 级 深度和根节点可以很容易地缓存。这只需要2-3 试图在树中找到任何东西。叶子也是这样“打包”的, 所以迭代树(例如全扫描或范围扫描)非常有效, 因为您每个块读取数百/数千个数据行(搜索)。

同样容量的二叉树有几十层 并且顺序访问每个值至少需要一个 寻找。 "

我了解 B-Tree 的节点(顺序)比 BST 多。所以它绝对比 BST 平坦而浅。

但是这些节点再次存储为链表对吗?

我不明白他们说密钥是作为一个块读取的,从而最大限度地减少 I/O 的数量。

同样的论点不也适用于 BST 吗?除了链接将向下?

请有人给我解释一下?

【问题讨论】:

标签: algorithm data-structures binary-tree binary-search-tree b-tree


【解决方案1】:

我了解 B-Tree 的节点(顺序)比 BST 多。所以它绝对比 BST 平坦而浅。我不明白他们什么时候说密钥是作为一个块读取的,从而最大限度地减少了 I/O 的数量。 同样的论点是否也适用于 BST?除了链接会向下吗?

基本上,在文件系统中使用 B+树的想法是减少磁盘读取次数。想象一下,驱动器中的所有块都存储为一个顺序分配的数组。为了搜索特定块,您必须进行线性扫描,每次找到一个块都需要 O(n)。对吧?

现在,假设您很聪明并决定使用 BST,太棒了!您会将所有块存储在 BST 中,大约需要 O(log(n)) 才能找到一个块。请记住,每个分支都是一个磁盘访问,这是非常昂贵的!

但是,我们可以做得更好!现在的问题是 BST 真的很“高”。因为每个节点的扇出(子节点数)因子只有 2,所以如果我们必须存储 N 个对象,我们的树将按照 log(N) 高的顺序排列。因此,我们最多只能执行 log(N) 次访问才能找到我们的叶子。

B+tree 结构背后的想法是增加扇出因子(孩子的数量),降低树的高度,从而减少我们为了找到叶子而必须进行的磁盘访问次数。请记住,每个分支都是磁盘访问。例如,如果你在 B+树的一个节点中打包 X 个键,每个节点将指向最多 X+1 个子节点。

另外,请记住,B+树的结构方式是只有叶子存储实际数据。这样,您可以在内部节点中打包更多键以填满一个磁盘块,例如,存储 B+树的一个节点。你在一个节点中打包的键越多,它指向的子节点就越多,你的树就越短,从而减少了为了找到一个叶子而访问磁盘的次数。

但是这些节点再次存储为链表对吗?

此外,在 B+树结构中,有时叶子以链表的方式存储。请记住,只有叶子存储实际数据。这样,使用链表的想法,当您必须在找到一个块后执行顺序访问时,您会比必须再次遍历树才能找到下一个块更快,对吧?问题是您仍然必须找到第一个块!就这一点而言,B+树比链表好得多。

想象一下,如果所有的访问都是顺序的,并且从磁盘的第一个块开始,那么数组会比链表更好,因为在链表中你仍然需要处理指针。 但是,根据 Tanenbaum 的说法,大多数磁盘访问不是连续的,而是对小文件(如 4KB 或更小)的访问。想象一下,如果你每次都必须遍历一个链表来访问一个 4KB 的块需要花费的时间......

这篇文章解释得比我好,而且还使用了图片: https://loveforprogramming.quora.com/Memory-locality-the-magic-of-B-Trees

【讨论】:

  • “另外,请记住,B+树的结构方式是只有叶子存储实际数据。” 万一有人读到这个(Q 本身要求B树)。这不是 B-tree 的要求,适用于 B+-tree。
【解决方案2】:

B-tree 的主要原因是它在变化时的行为方式。如果你有永久结构,BST 是可以的,但在这种情况下,哈希函数会更好。在文件系统的情况下,您需要一个在插入或删除时尽可能少地改变整体的结构,并且您可以在其中执行查找操作时尽可能少地读取 - 这些属性具有 B 树。

【讨论】:

  • 我不会说这是主要原因。这是高阶的固有结果。
  • 你说得对,我的意思是选择高阶 B 树作为文件系统索引的主要原因(在磁盘上,在内存中 Splay 树)。
【解决方案3】:

在磁盘存储中实现的 B 树中的每个节点都由一个磁盘块(通常为几 KB)组成,其中充满了作为数组访问的键和“指针”,而不是 - 正如您所说的那样 - 链表。块大小通常取决于文件系统,并选择有效地使用文件系统的读取和写入操作。这些指针不是普通的内存指针,而是磁盘地址,再次选择以方便支持文件系统使用。

【讨论】:

  • 你没有为文件名留下空间。
  • @EJP 什么文件名?大多数用于数据库的 B 树实现要么使用没有文件结构的裸分区,要么将整个树放在单个文件中。
  • 我指的是你现在删除的关于 NTFS 的评论,它是一个目录系统,它需要文件名作为键,磁盘地址作为指针。在计算块中元素的数量时,您遗漏了文件名。
【解决方案4】:

B 树节点本质上是一个数组,由一对{key, link} 组成,大小固定,可以在一个块中读取,通常是一些磁盘块。链接都是向下的。在底层,链接指向相关记录(假设为 B+-tree,就像在任何实际实现中一样)。

我不知道你从哪里得到链表的想法。

【讨论】:

  • 我认为 OP 中的语句 “这些 节点 再次存储为链表对吗?” 表明混淆可能来自事实是的,例如要在 B 树中搜索/获取数据,当您逐个节点遍历树时,需要遵循“链接”(查找)的序列。不过,这本身并不是一个链表,而且正如您也正确提到的,单个节点键通常存储为一个数组。
猜你喜欢
  • 1970-01-01
  • 2013-03-24
  • 2011-09-17
  • 2021-02-14
  • 1970-01-01
  • 2011-09-05
  • 2021-03-05
  • 2012-09-30
  • 2015-01-01
相关资源
最近更新 更多