9.1存储层次
- 主存储器:高速缓存和主存
- 第二级存储器:磁盘等较慢的设备
- 第三级存储器:光盘、磁带等
9.1.1磁盘
- 数据以磁盘块为单位存储在磁盘上。
- 块分布于同一张或多张盘片的同心环形磁道上,同一直径的所有磁道的组合称为柱面。
- 磁道可以进一步划分,得到的弧称为扇区,扇区的大小作为磁盘的特征不能改变。
- 读写一块时,磁头必须定位在块头位置。
- 目前系统至多允许一个磁头读写数据。
- 寻道时间:移动磁头到达所需块所在的磁道时间。
- 旋转延迟:所需块旋转到磁头下的等待时间,它的平均时间是旋转半圈所需要的时间,通常小于寻道时间。
- 传输时间:磁盘块到达磁头后的实际读写时间,即磁盘旋转经过数据块的时间。
9.1.2磁盘结构对性能的影响
(1)DBMS中数据必须在内存中操作
(2)磁盘与主存之间数据传输的单位是块,如果只需要块上的某一项,也需要传输整个块。读写一个磁盘块称为一次I/O操作。
(3)读写块的时间,依照块所在的位置而变化
存取时间 = 寻到时间+旋转时间+传输时间
9.2廉价冗余磁盘阵列(RAID)
- 磁盘阵列:就是把几个磁盘组织在一起的一种形式,以提高性能和改善存储系统的可靠性。
- 数据划分:以提高性能,将数据划分在几个磁盘上,让人感觉这几个磁盘想一个快速磁盘。
- 冗余:用于改善可靠性。
- 实现数据划分和冗余相结合的阵列称为独立磁盘冗余阵列(RAID)。
9.2.1数据划分
- 在数据划分中,数据被分成相等大小的段,并分到多个磁盘上。段的大小被称为划分单位。
- 数据段通常使用循环算法分布:如果磁盘阵列有D个磁盘,那么数据段i被写在i mod D磁盘上。
9.2.2冗余
- 通过存储冗余数据可以增加磁盘阵列的可靠性。如出现磁盘故障可使用冗余信息回复故障盘上的数据。
- 0级冗余:不维护冗余信息
- 1级冗余: 镜像,弄一份拷贝直接存储相关信息,并且没有划分,磁盘利用率50%
- 0+1级:划分和镜像,有时也称为10级RAID。利用率50%。
2级:错误校验码,使用的是汉明码,校验盘的数量随着数据盘数量对数式增长。
汉明码:来自百度百科
下列通用算法可以为任意位数字产生一个可以纠错一位的汉明码:
1.从1开始给数字的数据位(从左向右)标上序号, 1,2,3,4,5…
2.将这些数据位的位置序号转换为二进制,1, 10, 11, 100, 101,等。
3.数据位的位置序号中所有为二的幂次方的位(编号1,2,4,8,等,即数据位位置序号的二进制表示中只有一个1)是校验位
4.所有其它位置的数据位(数据位位置序号的二进制表示中至少2个是1)是数据位
5.每一位的数据包含在特定的两个或两个以上的校验位中,这些校验位取决于这些数据位的位置数值的二进制表示
(1) 校验位1覆盖了所有数据位位置序号的二进制表示倒数第一位是1的数据:1(校验位自身,这里都是二进制,下同),11,101,111,1001,等
(2) 校验位2覆盖了所有数据位位置序号的二进制表示倒数第二位是1的数据:10(校验位自身),11,110,111,1010,1011,等
(3) 校验位4覆盖了所有数据位位置序号的二进制表示倒数第三位是1的数据:100(校验位自身),101,110,111,1100,1101,1110,1111,等
(4) 校验位8覆盖了所有数据位位置序号的二进制表示倒数第四位是1的数据:1000(校验位自身),1001,1010,1011,1100,1101,1110,1111,等
(5) 简而言之,所有校验位覆盖了数据位置和该校验位位置的二进制与的值不为0的数。
采用奇校验还是偶校验都是可行的。偶校验从数学的角度看更简单一些,但在实践中并没有区别。校验位一般的规律可以如下表示:
观察上表可发现一个比较直观的规律:第i个检验位是第 位,从该位开始,检验 位,跳过 位……依次类推。例如上表中第3个检验位p4从第 位开始,检验4、5、6、7共4位,然后跳过8、9、10、11共4位,再检验12、13、14、15共4位。3级:位交叉检验
9.3磁盘空间管理
- 通常选择磁盘块大小作为页的大小,并且页面作为磁盘块存储起来。
9.3.1跟踪空闲块
- 方法一:维护一个空闲快的列表,当块被回收时,把它们放进列表备用。
- 方法二:维护一个位图,位图中保存每一个磁盘块,来说明它是否在使用。
9.3.2使用操作系统的文件系统来管理磁盘空间
- 操作系统也管理磁盘空间。通常操作系统把文件抽象成字节序列。数据库磁盘空间管理器可以建立在OS文件之上。
- 很多数据库不依赖于OS的文件管理系统,是因为DBMS的厂商不希望数据库的任何特征依赖于OS,增加移植性。技术原因是,32位系统中,OS最大文件是4G,而数据库需要保存更大的文件。
9.4缓冲区管理
- 在DBMS结构中,缓冲器管理器是负责在必要时把页面从磁盘取到主存的软件层。他通过把缓冲区划分成页集来管理可获得的主存,这些页集通常被称为缓冲池。
- 缓冲池中的主存页称为帧,即存放页的槽,
- DBMS高层代码的编写不需要考虑数据页是否存在于主存中。他们向缓冲区申请页,如果该页不在缓冲池中,则将该页读入缓冲池。高层代码在不使用该页时,也应该通知释放该页。
缓冲区管理如下图所示:
- 除了缓冲池本身,缓冲区管理器还维护一些信息,pincount和dirty。存放在某个帧中的当前页已经被请求但还未释放的次数,即该页的当前用户数,被记录在那个帧的pincount变量中。bool变量dirty表示页从磁盘读入缓冲池后是否被修改。
- 开始时,每个帧的pincount设置为0,dirty设置为false。当页被请求时,缓冲区做如下工作:
- (1)检查缓冲池中是否包含被请求的页,如果缓冲池中有该页,将该页的pincount增加1;如果缓冲池中没有该页,缓冲区管理器将按如下步骤,将该页读入缓冲池中:
- (a)根据替换策略选择替换帧,并且增加它的pincount。
- (b)如果替换帧的dirty为真,那么将该帧存放的页写回磁盘。
- (c)把请求的页读入替换帧。
- (2)把替换帧的主存地址返回给申请者。
- (1)检查缓冲池中是否包含被请求的页,如果缓冲池中有该页,将该页的pincount增加1;如果缓冲池中没有该页,缓冲区管理器将按如下步骤,将该页读入缓冲池中:
- 当调用缓冲区释放页的代码执行后,包含释放页的帧的pincount将减小。如果它修改了页的内容,同时也会通知缓冲区管理器,将该帧的dirty设为true.
- 如果缓冲池中没有pincount为0的页,并且需要存取不在缓冲池中的页,则缓冲区管理器在对请求页做出答复之前,必须等待某些页释放,
- 为防止出现两个事物请求同一页时的冲突问题,需要事先加锁,互斥锁或者共享锁。
9.4.1缓冲区替换策略
- 最近最少使用策略(LRU)
- 他通过维护一个pincount为0的帧队列来实现,每出现一个这样的一个帧,就将其插入队尾。
- 时钟替换是LRU的变体。
9.4.2数据库管理系统和操作系统的缓冲区管理
9.5记录文件
9.5.1堆文件的实现
页的链表
- 用一个双向链表来保存页,并将已经存满的页和有空闲的页分开存储,各设一个链表来保存。
- 但是这样在插入一个不定长的数据记录时,就需要扫描整个有空闲的链表,来查看某页是否有足够空间存放这条记录。
图示如下:
页目录
为了解决上述扫描问题,我们直接来维护一个目录并且在目录中记录每个页空闲空间的大小,以及该页地址。这样可以根据需要直接去找那一页.
9.6页格式
- 我们认为页由一组槽组成,每一个槽对应于一个记录。记录由
<page id, slot number>
对标识,
9.6.1定长记录
两种方法:
- 将所有空闲槽维护在页的末尾,每当有一个被删除时,在删除位置放入最后一个槽的记录,记录数减1。但是这样存在的问题是,万一移动了最后一个槽,然而那个槽正在被使用就会出错。所以有了第二种办法。
- 建立一个页头数组用来标识每一个槽是否为空,空则该槽对应的数组位置为1,否则为0。图示如下:
9.6.2变长记录
由于不能预设值槽的大小,所以只能需要的时候去分配大小。
- 维护一个槽目录,每个槽由<record offset, record length
组成,第一个表示从页上的数据部分开始到记录开始位置的字节偏移量。删除操作通过将offset设为1完成。
- 当需要插入数据时,首先扫描槽目录,查看那些没有指向任何记录的槽,也就是offset为-1的槽。如果这些空间不够存放这条记录,那么移动槽的位置,补齐空闲空间。将空闲空间留在页的末尾,维护一个指针指向空闲空间开始的地方。
- 注意删除槽的时候,不能直接删除槽目录中的记录,那样会改变后续槽的编号,从而影响rid。
一种将定长记录和变长记录以相同方式保存的方式
只保存槽的偏移量,槽的长度保存在开始的第一个位置。
9.7记录格式
9.7.1定长记录
很好保存,可以连续保存,用给定记录的开始位置加上前面记录的长度就可以完成定位一条记录。
9.7.2变长记录
第一种方法,用特殊符号分割不同的字段。
第二种方法,在记录开始处设置一个数组,用来保存每个字段开始(结束)的位置。
图示:
注意:
修改的时候问题会比较多,可能需要增加其长度,然后后面所有的数据记录都要动。或许在这个页存放不了了,只能移动到下个页。