【CMU 15-445/645 Database Systems】03 Storage-1

1,226 阅读7分钟

这是我参与8月更文挑战的第1天,活动详情查看:8月更文挑战

We will next learn how to build software that manages a database.

课程涉及的范围:

  • 存储
  • 执行
  • 并发控制
  • 恢复
  • 分布式数据库
  • 以及其他

1. Overview of storage

存储层次和访问速度

DBMS的设计基于这样的假定:数据库的基本存储,都是放在磁盘上的(non-volatile,非易失)。这种设计,称为disk-oriented DBMS。

DBMS管理数据在内外存之间的移动。disk IO代价很大,所以要尽量避免较大规模的内存失效和性能降级,尽可能的好好利用内存。

2. Disk-oriented

读取数据

  • client告知DBMS需要page2
  • 先从内存中查找
  • 内存没有,去disk查找
  • 将disk中的目录加载到内存,然后找到page2,加载到内存
  • 返回给client

其实这个逻辑跟操作系统加载数据是类似的,先在内存缓冲区中查找,若未命中就从外存中加载。若缓冲区已满,则使用内存置换算法来移出一块区域中的数据。

Why not use the OS

理论上,可以直接用mmap将数据库文件映射到进程的地址空间中,由OS来负责数据在内外存间的移入移出。

WHY NOT?

DBMS通常更了解你的数据

  • 把脏页根据正确的顺序写入disk
  • 特定的预加载
  • buffer替换策略
  • 进程调度和线程调度

 The OS is not your friend.

3. Database storage

How the DBMS represents the database in files on disk?

3.1 File storage

在磁盘上如何存放数据库 -> 将数据库中的内容按照文件的形式,存放在磁盘上。

  • OS对文件的内容一无所知。
  • 早期的一些DBMS会直接使用文件系统来进行存储。

Storage manager

维护数据库文件,有些有自己的读写调度逻辑,来尽可能的利用pages的时间和空间局部性;

将文件按照page的集合的形式维护,数据的读写都面向pages,并且维护可用空间;

3.2 Database pages

  • fixed-size的数据块
  • tuples,meta-data,indexes,log records都可以按照page的形式来存储
  • 每个page有自己的标识符
  • DBMS将page id映射到物理存储位置
  • 不同的DBMS的page size有所区别(512B-16KB不等,mysql是16KB)

完全类似于操作系统的逻辑地址和物理地址,逻辑地址中的页表、页号和物理地址中的帧。但是这里的物理存储位置一般是外存。

About page

在DBMS中会涉及到三个page的概念:

  • Hardware page(4KB usually)
  • OS page
  • Database page

需要注意的是,存储设备只能确保每一个hardware page的写入时原子操作;所以,当database page比hareware page要大的时候,DBMS就需要确保整个database page大小的数据在写入时的原子性。

Page storage architecture

不同的DBMS有不同的管理pages的方法:

  • Heap File Organization
  • Sequential / Sorted File Organization
  • Hashing File Organization

我们首先考虑page级别的管理,而非关心page中的内容。

Heap file

pages的无序集合。需要元数据来获知page的存在情况和是否有空间。

实现方式:

  • Linked List
  • Page Directory

如下,链表方式,两个HEAD节点来各自维护free page链表 和 data page链表。

每页中的空白位置(free slots)由page各自负责维护。

如下,目录页方式。通过一个特殊的目录页(Directory)来记录data pages的位置,也同时记录每个页中的free slots。

3.3 Page Layout

page header

每个页内,包括header和data两部分。header部分存储当前页的元数据:

Page size, checksum, DBMS version, transaction visibility, compression information

Self-contained: means that all the information needed to read each page is on the page itself.

page layout

介绍数据在页内如何存储:

tuple-oriented

  • 稻草人模型:

直接按顺序存储各个tuple,带来的问题是:删除某个tuple会导致乱序;tuple中存在不定长的属性会导致无法寻址;

  • 正确的方案:slotted pages

有一个slot array,将slots映射到每一个tuple的初始存放位置。slot array从前往后、tuple从后往前插入。

如下图,header中需要额外维护已经使用了的slots的数量;最后一个使用的slot的offset(来用于插入新数据);当slot array与data相遇时,我们认为这个page已经存满了。

(但是如果删除某一个tuple,如何解决碎片问题?)

log-structured

存储日志信息,每一次db有修改的时候,就追加操作记录到该文件中。

  • insert:存储整个元组
  • delete:标记被删除
  • update:只标记修改的部分

回溯日志表,找到所有和这个id相关的记录(通过索引),来复现这条记录。

可以构建索引,来便于查找记录。

定期压缩日志(将对同一条数据的操作的最终结果记录下来,替换多条相关日志)。

显然,这种方式对只有追加写的场景非常友好。读相对慢。

3.4 Tuple layout

tuple本质上就是字节序列。DBMS需要把字节给翻译成对应的属性类型和值。

Tuple header

tuple也有元数据,称为 tuple header,包含可见性信息(用于并发控制,例如哪一个事务正在创建/修改了这个tuple)以及标记null值的bit map。

不需要在这里存储关于数据库schema的元数据。

Tuple data

属性通常都是按照创建表时的顺序存储;多数数据库不允许tuple size > page size。

Unique identifier

每一个tuple都有唯一标识符,通常是pageid + (offset / slot)

应用程序不可以使用这些标识符来做其他事情

Denormalized tuple data

将相关的属性自动存放到一起(类似join?)

一定程度上减少了I/O数量,但update的开销大大增加。

4. 总结

以上讨论了 寻找page的方法,page的存储方法,元组的存储方法。

数据库中的数据,究其根本,是以文件的形式存储在磁盘上的。

那么就要考虑以下几个问题:

  • DBMS如何管理这些数据库文件?包括数据定位、数据拆分、如何高效的访问这些文件等等;
  • 每一条数据在文件中具体是如何存储的?

首先,为了管理方便,数据按照固定大小的块来进行组织,每一块称为一页(page);每个文件中可以有多个页。那么我们需要有一套逻辑,来维护和定位文件中的页。这里详细介绍了heap file这种方式,以及从文件中定位页的两种方法:链表结构和使用目录页。

现在我们找到了所需的页,然后思考每一个页是如何设计的,也就是页的布局。就像计算机领域很多的设计一样,页的最开头,需要一个header部分来存储元数据(包括页的大小、校验和、版本信息、压缩信息等),然后就是data部分存放的具体数据,这里介绍了两种data部分的布局方法:朴素的直接存储元组,和类似append-only files的记录操作日志,用复现的方式来获取数据。

现在我们找到了所需的元组(tuple),也就是某一条数据,现在思考每个tuple是如何设计的。既然细化到了某一条,那么它需要一个标识符id,以及数据部分按顺序记录每一个属性的值。要注意的是,每一个tuple仍然有自己的header,用来进行并发控制,以及记录该条记录中的空值。

通过以上三个步骤,我们能够找到文件中的页,页中的元组,然后查看元组的各个属性。但是disk IO总是慢的。database file存放在外存中,我们每次要访问某个文件中的某个页时,总是需要将这个页(页也是进行数据库操作的基本存储单位)加载到内存中。 所以就像操作系统加载数据到内存中一样,我们也希望能尽量好的利用数据的空间和时间局部性,利用相对有效的页面置换算法,来减少从外存中加载页到内存的次数。显然,我们可以直接调用OS的既有逻辑来进行页面管理(mmap),但是我们有DBMS,它既然是专门负责管理数据库的,一定是对数据更了解的,更可以因地制宜的进行策略的选择。所以,通常都是由DBMS来设计这一套操作逻辑。

毕竟,OS is not your friend.