10.内存层级和文件组织
磁盘和文件
- DBMS 将信息存储在(“硬盘”)磁盘上
- 磁盘是一个序列字节,每个字节都有一个磁盘地址
- READ:从磁盘读取数据到主存( main memory,RAM )
- WRITE:从主存写数据到磁盘
- 数据在磁盘上的存储单元为块 - block ,又称为页 - page
- 每个页面都有固定的大小,比如 512 字节。它包含一系列记录
- 在许多(并非总是)情况下,页面的记录具有相同的大小,例如 100 字节
RAM:也叫主存,是与 CPU 直接交换数据的内部存储器。它可以随时读写(刷新时除外),而且速度很快,通常作为操作系统或其他正在运行中的程序的临时数据存储介质
- 为什么主存不能存储所有东西
- 价格:RAM 比磁盘贵得多
- 主存不稳定( volitile ):即一旦断电所存储的数据将随之丢失。要求:每次程序执行完毕,数据能被存储。
存储层级:
- 当前使用的数据存在主存( RAM )
- 主要的数据存储放在磁盘上面(二级存储)
- 用于归档旧版本数据的磁带 - Tape(三级存储)
- 数据和成本减少的同时,存储容量增加
磁盘的组成
- 一个 block 包含多个扇区( sector )
文件组织
- 数据库存储为文件 file 的集合,每个文件都是一个记录序列,一个记录包含着若干个字段 - fields(属性值)
- 一个文件相当于一个表,即 relation 实例
- 一个记录相当于表格中的一行
- 一个表格中的记录大小是固定的
- 如何组织记录存放在文件里面?
- 固定大小记录
- 可变大小记录
固定长度记录
- 一般方法
- 存储记录 i 从第 \(k × ( i - 1 )\) 个字节开始,于 $ k × i - 1$ 处结束,记录大小为 k
- 同个文件的记录可能跨 block 存储(单个 block 不够)
- 删除记录 i 时应如何操作?
- 方法1:移位记录,即将记录 i + 1,......,n 移动到 i,......,n-1
- 方法2:将记录 n 移动到 i
- 方法3:利用一个 free list 回收这些被释放出来的空间
Free list
每个记录增加一个指针,在文件中增设一个文件首部,记录文件中的有关信息,其中有一个指针指向第一个被删除记录的位置,所有被删除结点用指针链接,构成空闲记录链表
可变长度记录
- 在数据库系统中,可变长度以多种方式出现
- 文件存储了多种不同的记录类型记录
- 文件中允许的记录类型的字段是变长的
- 允许记录中某个字段可以出现重复,如数组或多值集合
- 简单(但不好)的解决方案:字节字符串记号表示记录结尾
- 将(⊥)控制字符附加到每个记录的末尾
- 删除困难(释放的空间碎片化)
- 插入困难(移动记录很困难)
方法一:符号方法
预先分配最大可能长度,插入记录时用符号 ⊥ 填充未用到的部分
方法二:指针方法
对于某些具有重复属性的记录类型很有用
文件中的两种块:
- 锚定块:包含链的第一条记录
- 溢出块:包含溢出字段
文件中记录的组织方式
- 无序存放:有空间就可以放
- 顺序存放:按某个搜索键的值的顺序存放
- 哈希存放:根据每个记录的搜索键计算哈希值,结果指定记录应存放在哪个块中
这里的“搜索键”与关系模型中的 key 不是一个概念,这里的搜索键是指存储时,被制定用来参考,以排放记录的属性
譬如学生表,我们可以用学号作为搜索键进行排放,也可以用名字,如果用名字的话可能会有重名,此时该重名键指向的地址,则应顺序排放了所有该名字的学生
无序存放:堆排序
- 为了实现在记录这个维度上的操作,我们需要
- 记录每个 file 所存放的 pages
- 记录 page 的剩余空间
- 记录每个 page 存放了记录的位置
- 使用页目录的堆文件
- 目录中指向每个 page 的条目中也可包含其剩余空间信息
- 目录本身亦是 page 的集合;此处链表实现只是一种选择
顺序文件组织
- 适用于记录总是被根据某个属性值连续访问的场景
- 擦除:用指针跳过该记录
- 插入:找到要插入记录的位置
- 如果有可用空间就插入那里
- 如果没有可用空间,则将记录插入到溢出块中
- 需要不时地重新组织文件以恢复顺序
使用哈希(散列)作为文件组织
- 假设有 10 万条员工记录,我们每页可以放 100 条记录,那么我们需要 1,000 页
- 我们为表分配 1,2000 个 page,以便为将来的插入留出一些空间
- 设计以工资为搜索键的哈希寻址函数为:
- 优势:对记录进行寻址时,只需要一次哈希计算
- 当我们插入一条新纪录的时候,我们计算工资的哈希函数并将该记录插入相应的 page
- 如果该 page 已满,我们将创建一个溢出页面,并在那里插入新纪录
- 可以有效回答诸如“查找所有工资为 15,000 的员工”的查询
- 计算 15000 的哈希值,然后只对对应的桶中查找,如果没有溢出桶,则只需一次读取即可回答查询
- 如果存在溢出桶,我们必须读取所有的桶
- 散列发不适用于范围搜索(“查找薪资在 15,000 到 16,000 之间的所有员工”),因为这些员工可能分布在不同的存储桶中
时间成本分析
- 忽略 CPU 的时间成本( 相比磁盘读写操作时间小得多 ):
- 以读写 page 的总次数作为衡量单位
- 平均情况分析,它基于单个记录的插入和删除操作,伴有一些假设:
- 堆文件
- 搜索操作:寻找特定键值的记录,并只能有一个匹配
- 插入操作:总是在文件末端进行插入
- 顺序文件
- 每次删除/插入后对记录进行整理,保证顺序
- 搜索同上
- 哈希文件
- 没有溢出页面,所以我们不需要到溢出页面进行操作
- 没有溢出页面,所以我们不需要到溢出页面进行操作
- 堆文件