B树索引是如何利用在硬盘上的?

游离失所 2016-08-09 03:23:14
假如B树存储的是索引的键,以及键所对应的内容的硬盘上存储地址。

那么问题来了。

1.索引往往都是很大的,往往都存在硬盘上。我不可能一次性都读取出来。然后在内存中来进行查找比对,然后再到硬盘对应的位置把数据取出来。这样我还用B树来构建索引干鸟。那数据库索引是怎么工作的呢?

2.基于问题1。假设B树不但存储了索引的键,还有对应内容的地址,他还存储了他的孩子节点的地址。那么我们可以每次只读取一个节点,然后进行比较。如果没找到,则根据条件跳到下一个节点继续查找。这样没问题,但是这个索引文件我们如何构造?一个个节点的地址如何生成?又如何通过程序根据这些地址去获取到数据?最后又如何将一个个节点的内容保存起来生成一个索引文件?

简单的来说,我就是想自己构建一个非常微型的数据库。。关于数据库索引的文章非常多,也有很多结合了硬盘来说。。但都非常不全面,没有说到具体怎么去在硬盘上构建索引,以及利用索引在硬盘上进行查找。。希望大家帮忙解答下我心中的疑问,我非常苦恼这个问题。。

有学习材料更好。。语言最好是C++或C#的。。
...全文
471 10 打赏 收藏 转发到动态 举报
写回复
用AI写文章
10 条回复
切换为时间正序
请发表友善的回复…
发表回复
xuzuning 2016-08-10
  • 打赏
  • 举报
回复
文件在硬盘中是以族为单位存储的,所以你在组织树节点数据时最好不要超过族的规模 这样读取时就是最快的
  • 打赏
  • 举报
回复
引用 楼主 lyj224170707 的回复:
简单的来说,我就是想自己构建一个非常微型的数据库。。关于数据库索引的文章非常多,也有很多结合了硬盘来说。。但都非常不全面,没有说到具体怎么去在硬盘上构建索引,以及利用索引在硬盘上进行查找。
事实上,如果你是开发一个“微型”的数据库,那么你完全可以在运行时、系统初始化时才临时创建索引,在系统关闭之前将索引序列化到磁盘(例如文件头部的“链表4”来记录顺序记录序列化了得索引数组的起始地址)。假设关闭之前若没有正确保存索引,则下次初始化启动时则重建索引,否则就读取上次保存的值在内存中反序列化。对索引可以稍微简单粗暴地处理。
  • 打赏
  • 举报
回复
2. 这个问题,在任何一本关于数据库原理的教科书上都有。注意我说的是“数据库原理”,而许多人学过的可能只是简单应用(也就是职业教育的入门教程,而非针对从事研发工作的人的教程)。 你找一个数据库原理方面的书,它会告诉你通用的关系数据库系统如何设计自己的虚拟数据块(书上可能翻译为“虚拟磁盘块”),数据块列表(使用中的、空闲的),例如每块1M大小。 一个文件内部,可以包括多个虚拟数据块。每一块都有一个指针链接到下一块。同时文件头部可以有几十字节固定区域,用来定义诸如“链表1、链表2、链表3、链表4的起始偏移”,以及“最大链表长度、多少分钟压缩合并一次空闲”等等全局设置。 每一数据块中保存多条记录,因此每一个记录的“地址”其实就是“文件内磁盘块地址+磁盘块内数据数组下标”。 当数据被创建时,可以插入“某个正在使用的”磁盘块的空闲空间中(同时因为块内空闲空间的),如果没有则从空闲磁盘块列表上取下一个磁盘块使用,如果还没有则动态扩大文件(例如1M空间)来分配一个磁盘块使用。 当数据删除时,它可以挪动磁盘块内的空间(使得空闲部分集中到尾部)。如果数据原来是磁盘块中唯一一个,则磁盘块变为空闲。如果数据不是原来磁盘块中唯一一条数据,则磁盘块在“使用中的磁盘块”的链表的位置可能因为空闲增大而向前移动。 所以,一个普通的可随机读写的文件,囊括了数据库系统所有数据。而并不需要分成许多文件。 数据的“所在数据块编号”不一定是绝对对应于文件中的偏移地址,完全可以在数据库系统初始化时一次性扫描所有数据块,在内存中创建字典数据结构。如果说单个索引可以不一次性读入内存,但是这个数据块编号跟数据块的文件偏移地址的对应关系,则一定要一次性读入内存的。
  • 打赏
  • 举报
回复
1. 索引即可能全都读取到内存,也可能不全部读取到内存,不同数据库系统的实现有所不同。 索引并不大,所以把单个索引一次性地读入内存也是可以的。例如一个数据表可能有100M 空间,其索引可能只占用200K。除非你是把一条记录里边几乎所有字段都组合起来作为索引键,否则怎么可能索引跟数据的大小类似呢? 假设数据库有100个表、200个索引,不必一次把所有索引都读入内存,用到哪一个再读哪一个。类似地,你也可以在读取索引时仅仅读取其顶层对象在内存中创建映射,而将下一级的节点使用一个自定义的 Lazy 机制对象(也就是说比普通对象来说,多一个判断是否“有值”的功能和一个“加载”功能),需要扩展哪一个节点时才读取某个节点的下一层节点。 从性能上说,读取整个(单个的)索引到内存里是性能和功能很好的平衡。动态加载节点则有可能过于谨慎。
游离失所 2016-08-09
  • 打赏
  • 举报
回复
引用 4 楼 Forty2 的回复:
[quote=引用 1 楼 lyj224170707 的回复:] 我的想法是先获得索引文件的流。。然后根据我们定义的规则(比如说64个字节为一个节点)先读取0-64,然后进行比较。如果当前节点没有,则跳到下一个节点进行查找。当然,我们有存储下一个节点的位置。。比如说是在128。。我们就读128-192。。然后继续下去。。但感觉数据库不是这么干的。。
这样想法并不对,可能你没有理解B-Tree的原理。 简单的说,B-Tree不需要一个节点一个节点第顺序寻找。它只要枝干分支,分支跳分支等等。而每个节点占用的内存可以很小。比如5阶b-tree每个节点最多放5分支索引。 以下是科普文章(希望链接能打开): https://zh.wikipedia.org/wiki/B%E6%A0%91[/quote] B树为什么不需要一个节点一个节点顺序找? 在我看来他跟平衡二叉树和红黑树不同的一点就是高度问题。。它是平衡多叉树。。 如果每次跳跃的动作相当于硬盘的一次寻址操作,降低树的高度就比较重要了。。m阶b-tree每个节点最多有m个孩子。。m>=2。。这个没问题。。 我纠结的是在硬盘上是怎么玩的
zhouzangood 2016-08-09
  • 打赏
  • 举报
回复
路过帮顶!
Forty2 2016-08-09
  • 打赏
  • 举报
回复
引用 1 楼 lyj224170707 的回复:
我的想法是先获得索引文件的流。。然后根据我们定义的规则(比如说64个字节为一个节点)先读取0-64,然后进行比较。如果当前节点没有,则跳到下一个节点进行查找。当然,我们有存储下一个节点的位置。。比如说是在128。。我们就读128-192。。然后继续下去。。但感觉数据库不是这么干的。。
这样想法并不对,可能你没有理解B-Tree的原理。 简单的说,B-Tree不需要一个节点一个节点第顺序寻找。它只要枝干分支,分支跳分支等等。而每个节点占用的内存可以很小。比如5阶b-tree每个节点最多放5分支索引。 以下是科普文章(希望链接能打开): https://zh.wikipedia.org/wiki/B%E6%A0%91
游离失所 2016-08-09
  • 打赏
  • 举报
回复
引用 2 楼 starfd 的回复:
感觉你可以参考这个 http://www.cnblogs.com/CareySon/archive/2012/04/06/Imple-BTree-With-CSharp.html
这个看过了。。这个是建立在内存的基础上的。。
游离失所 2016-08-09
  • 打赏
  • 举报
回复
我的想法是先获得索引文件的流。。然后根据我们定义的规则(比如说64个字节为一个节点)先读取0-64,然后进行比较。如果当前节点没有,则跳到下一个节点进行查找。当然,我们有存储下一个节点的位置。。比如说是在128。。我们就读128-192。。然后继续下去。。但感觉数据库不是这么干的。。

110,534

社区成员

发帖
与我相关
我的任务
社区描述
.NET技术 C#
社区管理员
  • C#
  • Web++
  • by_封爱
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告

让您成为最强悍的C#开发者

试试用AI创作助手写篇文章吧