【数据库基础】3. 文件结构

本文详细介绍了数据库文件结构,包括记录的结构(定长记录和变长记录)、块中记录的组织方法(定长记录和变长记录)以及文件中记录的组织方法(顺序文件、B+树文件、散列文件和多表聚簇文件组织)。讨论了各结构的优缺点及其适用场景,以提高数据库的访问和操作效率。

文件结构


之前说过,数据库一般被保存在磁盘上,通常情况下,保存在磁盘上的数据库以文件的形式组织,文件由计算机操作系统来维护,因此,数据库系统只需要考虑文件的结构即可

数据库的块是数据库读写文件的最小单位,之前介绍过的磁盘块,是计算机系统读写磁盘的最小单位,因此,数据库的块必须是磁盘块的正整数倍,之后不再区分数据库的块与磁盘块,而是将它们统称为块

对于一组模式相同且只包含定长属性的记录,我们称它们为定长记录,否则我们称它们为变长记录,定长记录和变长记录的结构不一样,变长记录的结构要复杂一些

文件的结构实际上包含三部分内容:

  1. 记录的结构
  2. 块中记录的组织方法
  3. 文件中记录的组织方法

记录的结构

设计记录的结构时,需要保证记录的属性易于访问

定长记录

定长记录的结构如下:

空位图属性 1属性 2⋯\cdots属性 nnn

定长记录的结构类似于 C 语言的结构体,所有属性的值被连续的存储在记录所占据的空间中

除了属性之外,定长记录可能还会存储一个空位图,空位图是一个二进制串,长度与记录的属性个数一致,二进制串的第 iii 位是 1 表示记录的第 iii 个属性的值是 NULL ,第 iii 位是 0 表示记录的第 iii 个属性的值不是 NULL

如果定长记录的某个属性的值是 NULL ,为了保证和其它记录长度一样,我们依然要在记录中给这个属性分配空间,但保存的属性值毫无意义

在 C 语言中存在一个被称作结构体对齐的机制,有些处理器在读写内存时,必须从内存地址是 4 的倍数或 8 的倍数的地方开始,因此内存中的结构体的一些相邻变量之间,可能会空出一点空间不用,从而减少访问某些变量所需的时钟周期,类似于 C 语言中的结构体,如有必要,也可以对定长记录中的属性进行对齐

需要注意的是,只有当定长记录从磁盘被读取到内存中,对齐才会起作用,但我们在磁盘中存放定长记录时,就应该将其中的属性对齐,否则在记录被读取到内存中时,还需要额外对齐一次

访问定长记录的属性需要记录的模式信息,我们只需要为所有模式相同的定长记录额外保存一个模式信息即可,比如对于一个存放定长记录的块,我们只需要在块首保存记录的模式信息,就可以访问到块中任何记录的任何属性

变长记录

变长记录长度不定的原因有很多:

  1. 几种模式不同的记录存储在同一个块中
  2. 记录的某些属性是不定长的
  3. 记录的某些属性是可重复的(虽然这违反了第一范式)

本节中我们只考虑第二个原因造成的变长记录

由于不同的记录长度不定,要想访问到变长记录的属性,就需要变长记录能够自描述,变长记录的结构分为定长部分和变长部分,其中定长部分中包含了自描述信息,通过定长部分的自描述信息,我们就可以访问变长部分了

变长记录的结构如下:

在这里插入图片描述

定长部分保存了所有的定长属性,变长属性实际存储在变长部分,但在定长部分中为每个变长属性存储了两个整数——变长属性的长度以及首地址偏移量,它们构成了该变长属性的自描述信息

定长部分还保存了一个空位图,和定长记录不同,如果变长记录中某个变长属性值为 NULL ,我们完全可以不给这个属性分配空间,但如果定长记录属性值为 NULL ,我们还是需要给其分配空间

块中记录的组织方法

设计块中记录的组织方法时,需要保证块中的记录易于访问,此外还需要易于向块中插入和删除一条记录

定长记录

在块中组织定长记录较为容易,只需要用一个定长记录的数组来保存记录,就可以做到随机访问块中任何一个定长记录

一般情况下,一个记录不应该跨块存储,因为这意味着访问这条记录需要两次块访问,如果一个块的大小不是记录大小的整数倍,我们将多余的空间废弃不用

从块中删除一条记录时,我们不必真的回收这条记录所占的空间,因为通常情况下插入操作比删除操作更频繁,我们可以使用一个链表维护所有被删除的记录,称作空闲列表,删除记录时,只需要将其添加至空闲列表中即可

插入一条记录时,由于有空闲列表的存在,可以很容易地定位到一个被删除的记录,然后将那条记录改为待插入的记录,如果空闲列表为空,则将记录插入到数组末尾

空闲列表的头节点被保存在块首,其它节点保存在被删除的记录中

变长记录

我们用分槽的页结构(slotted-page structure)来在块中组织变长记录:

在这里插入图片描述

分槽的页结构可以分成三部分:块首、记录和空闲空间

块首存储了记录个数,空闲空间尾地址的偏移量,并且为每条记录保存了长度和首地址偏移量

由于块首存储了所有变长记录的描述信息,因此访问一条记录时,可以先访问块首,找到这条记录的长度及首地址偏移量,之后就可以直接定位到该记录

从块中删除一条记录时,将记录所占的空间回收,滑动所有位置在被删除记录之前的记录,使得所有记录占用的空间连续,此外,块首中还存放着记录的描述信息,要修改被删除记录的描述信息,用来标记这条记录已被删除,例如将记录的长度改为 -1

插入一条变长记录时,把这条记录放到空闲空间的尾部,并在块首部分加入这条记录的描述信息

无论如何插入和删除,空闲空间都是一段连续的空间,介于块首和记录之间

文件中记录的组织方法

有几种常见的在文件中组织记录的方法:

  1. 堆文件组织:记录按任意顺序放在文件中
  2. 顺序文件组织:记录按某个属性或属性集的值的顺序存储在文件中
  3. 散列文件组织:根据记录的散列函数值,决定将记录保存在文件的哪个块中
  4. 多表聚簇文件组织:在一个文件块中保存两个或更多关系的记录,这样的文件组织可以加速某些类型的查询
顺序文件组织

顺序文件中记录大致按某个属性或属性集的值排序,这种组织方式可以加速某些类型的查询,之所以说是大致排序,因为将记录严格排序效率太低,而且没有必要

由于记录只是大致排序,因此我们需要用一个有序链表,将所有记录按序连接起来

删除一条记录时,只需要定位到这条记录所在的块,从块中删除这条记录,同时更新有序链表,如何从块中删除一条记录已经在之前讲过了

插入一条记录时,先定位到这条记录应该插入到哪个块,然后将这条记录加入块中,同时更新有序链表,因为存在有序链表,所以一个块中的记录没必要按照指定的属性或属性集排序,就可以通过有序链表快速地按顺序访问,如果待插入的块已满,有一个解决方法是使用溢出块,将待插入的记录存放至溢出块,同时更新有序链表

根据上面插入和删除的策略,我们可以看出,不同块之间的记录的大小关系是确定的,后一个块中任何记录在指定属性上的值一定大于前一个块中的记录,因此我们可以通过二分查找,快速定位到一条记录所在的块

需要按指定属性的值的顺序遍历整个文件中所有记录时,我们只要在有序链表上遍历一遍即可,所需的块访问次数不会比文件的总块数多很多,当溢出块过多时,遍历的效率会下降,这时就需要对文件进行一次开销很大的重组

B+ 树文件组织

B+ 树文件组织是顺序文件组织的改进版,顺序文件中记录大致按某个属性或属性集的值排序,而 B+ 树文件组织中,记录以某个属性或属性集为搜索码,存放在 B+ 树中

B+ 树的一个节点存放在文件的一个块中,叶节点与普通的 B+ 树不同,存放的不是搜索码及指向对应记录的指针,而是直接存放记录

B+ 树文件的插入、删除、查询本质上都是 B+ 树的插入、删除、查询,之前已经介绍过了,B+ 树文件组织在保留了顺序文件组织的优点以外,还避免了开销很大的重组操作,时间效率很高,但 B+ 树文件组织由于额外存储了非叶节点,空间效率略低

散列文件组织

通过散列函数将记录映射到文件的某个块上,既可以用静态散列,也可以用动态散列,优点是插入、删除和查询的效率高,缺点是不能按搜索码值的顺序遍历所有记录

如果一个表以 B+ 树文件或散列文件的形式组织,相当于这个表自带了一个主索引

值得注意的是,对于动态散列文件组织和 B+ 树文件组织,记录存放的位置会频繁变动,如果在这个文件对应的表上创建了辅助索引,就会出现问题,例如 B+ 树文件的一次插入导致了一个块的分裂,那么辅助索引中所有指向这个块的指针都需要更新,由于是辅助索引,因此这些指针可能分布在不同的块中,因此对 B+ 树文件的一次插入可能会导致很多次块访问,这显然是我们无法接受的

解决上述问题的办法是,如果一个表以 B+ 树文件或动态散列文件的形式组织,那么其上创建的所有辅助索引,并不保存任何指向记录的指针,而是保存每条记录在主索引的搜索码上的值,这样通过辅助索引定位一条记录需要两步,首先在辅助索引中找到记录在主索引的搜索码上的值,然后再在主索引中实际定位

多表聚簇文件组织

考虑下面这类查询:

select *
from r1 nature join r2

实际应用中,自然连接和等值连接是相当常见的,多表聚簇文件组织通过将多个表的记录组织在同一个文件,起到对自然连接和等值连接的加速作用

具体来说,要想给多个表的连接加速,首先要指定一个这些表都包含的属性或属性集,之后我们将在指定的属性或属性集上相等的记录尽量存放在一起,而不管这些记录是否是同一个表中的

虽然多表聚簇文件组织可以加速连接,但会导致很多其它类型的查询变慢,例如遍历一个表的所有记录,是否对多个表使用多表聚簇文件组织,要根据预期的查询类型来决定

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值