数据库管理系统将数据存储在磁盘、磁带以及其余的裸设备上,虽然这些设备的访问速度相比内存慢不少,但其非易失性和大容量的特色使他们成为数据存储的不二之选。html
本文主要讨论大型数据库产品的磁盘存储内部结构,这对于深刻理解数据库各类数据结构具备相当重要的做用。数据库
数据库磁盘存储的体系结构服务器
以上两图分别展现了存储器分级结构以及磁盘内部物理结构,不是本文重点,不赘述。须要强调的是:一次完整的输入输出(IO)操做的时间=磁盘轴旋转时间(旋转延迟)+磁盘臂移动时间(寻道时间)+数据传输时间。三者所需时间的平均经验值为:0.004秒、0.008秒和0.0005秒。因此,一次完整的IO时间的经验值是0.0125秒,即1/80秒。数据结构
对于大型数据库而言,即使是这极短暂的0.0125秒,频繁的IO操做会将这微不足道的时间累积得很是可观,所以磁盘存储的优化对于数据库效率的提高是很是必要和重要的。不一样的数据库产品的磁盘存储内部实现是不一样的,本文只讨论Oracle、DB2大型数据库产品,两者细节上虽有不一样,但结构大致上是同样的。并发
Oracle和DB2数据库的存储模型如图:oracle
能够看出,数据库中的数据都存储在表空间中。表空间便是管理将逻辑数据库设计映射到操做系统物理存储中的一个数据库对象,用于指明数据的物理位置。关于表空间,之后再讨论。jsp
Oracle数据库磁盘存储的逻辑结构为:一个数据库(Database)对应多个表空间(Tablespace),一个表空间对应多个段(Segment),一个段对应多个区(Extent),一个区对应多个数据块(Data Block),真正的数据就保存在数据块中。这里有如下几点须要说明:数据库设计
1.Oracle中一个数据块的大小默认是2KB(支持2KB,4KB,8KB,16KB,32KB),而DB2中则默认是4KB(支持4KB,8KB,16KB,32KB);性能
2.Oracle中有段(Segment)的概念,而DB2中没有这一律念,表空间直接是各个容器(数据文件)中的区(Extent)组成,不过也仍是有一个很弱化的Extent组概念。下面提到的关于Segment的内容则所有是针对Oracle的;优化
3.Oracle中的数据块称为Oracle Block,而DB2中则直接称为Data Page(数据页)。
4.Oracle中的Extent称为区,而DB2中则称为扩展数据块。为方便阅读,本文中统称为区。
Oracle磁盘存储逻辑结构
DB2磁盘存储逻辑结构
要注意:这里的表空间,段,区,数据块(页)所有都是数据库中的逻辑概念,并非物理存在的,那么数据库磁盘存储的逻辑结构如何映射到操做系统磁盘存储的物理结构中呢?
先来看看表空间的物理映射。表空间在操做系统上是由容器(Container)承载的,对于系统管理表空间(SMS)【注意:Oracle不存在系统管理表空间,其表空间所有都是数据库管理的】,其惟一的容器是文件目录;而对于数据库管理表空间,其容器则是文件或者裸设备(好比磁带、磁盘柜)。这里咱们不讨论系统管理表空间,只关注数据库管理表空间下的数据库磁盘存储。因为数据库对于文件和裸设备这两种容器操做上是同等对待的,因此以文件容器为例进行讨论。文件容器自己是一个由DMS表空间使用的预分配大小的文件,一个表空间能够有多个文件容器,即有多个数据文件。也就是说:一个逻辑上的表空间映射为多个物理上的数据文件。
再来讨论数据块(页)的物理映射。咱们知道,物理结构上,操做系统中的文件是由多个操做系统的块(Block)组成的(Linux,Unix系统的块大小为512B,而Windows系统的块大小为1KB),而上面说了,数据库中的数据是以数据块(页)为单位存放的,,那么数据库中的数据块(页)和操做系统的块是什么关系呢?事实上,若干个操做系统块组成一个数据库的数据块(页)。对应区(extent)和段(segment)的映射并无物理单位与之对应,而是在一个数据文件中会包含多个段,每一个段里又包含多个区(每一个段中的区的个数不必定是同样的;DB2中数据文件中直接以区为单位,没有段的概念),每一个区包含若干数据块(每一个区中数据块的数量也不必定同样)。另外,和表空间同样,段也是能够跨文件的,即一个段能够由不一样文件中的区所组成。
数据库磁盘存储的逻辑/物理映射图解以下(DB2中没有Segment这一层):
关于这些逻辑单位的具体讨论之后再说。如今只须要了解大致的体系结构。经过上面的介绍能够看到,数据库管理的表空间自成一体,具备平台无关性,俨然是一个小型的独立文件系统了。
数据库磁盘存储的内部实现
了解了磁盘存储的体系结构,再来看一看数据库系统中,数据具体是如何进行存储的。
当建立一张表(Table)的时候,会为其指定表空间,一旦表成功建立,数据库系统就要为表提供磁盘空间。
Oracle数据库会自动为一张表分配一个Segment(段),这个Segment称为Data Segment(数据段)【注:一张表只能被分配一个数据段。Oracle一共有四种类型的段,分别是Data Segment(数据段),Index Segment(索引段),Rollback Segment(回滚段)和Temp Segment(临时段)】。当为表分配的数据段所有写满的时候,数据库管理系统会为这个数据段增长新的区(Extent),也就是说,数据段空间分配完后并非须要多少空间就为段增长多少空间,也不是直接在区中增长数据块,而是一次性增长一个Extent(这样作避免了频繁的Segment扩容),Extent是空间分配的最小单位,并且Extent在表空间中的各个容器上是均衡分配的。另外,数据块(页)是最小的存储单位,也即最小的I/O单位,全部数据都是按块(页)存储,读出的时候也是直接将整个数据块(页)读入内存中的。至于DB2,其方案与Oracle基本相同,所不一样的是没有Segment分配的问题。
咱们以DB2为例,看看数据存储具体是怎样的。【参考牛新庄:深刻解析DB2】
一个DMS表空间能够有多个容器(文件或裸设备),DB2将Extent均衡的写到各个容器上。即当须要请求一个Extent时,数据库管理器这个Extent分配到下一个容器上。这种方案保证了各容器的均衡利用,提升了并行访问效率。如左图:
表空间容器均衡写
表空间容器,Extent,数据页和表空间之间的关系
新建一个称为HUMANRES的DMS表空间,其Extent大小为2个Page(即数据块),每一个Page大小为4KB。表空间有4个容器,每一个容器内有少许已分配的Extent:表空间中DEPARTMENT和EMPLOYEE表中都占用了7个Page,按照上面介绍的分配规则,这两个表中的数据都会写到四个不一样的容器中(7个Page须要分配4个Extent,每一个Extent依次分配到各个容器中),另外,一个Extent只能由一个表所写,即使表数据不能彻底利用Extent中的空间,Extent中的空闲空间也只能空着,不能继续写入其余表中的数据(这是由Extent是空间最小分配单位决定的)。如右图。
数据块(页)存储
下面进一步深刻,分析一下数据库磁盘存储最小单元数据块(Data Block or Data Page)内的具体结构是怎样的。对于Oracle和DB2,两者的数据块结构是不一样的。如下分别讨论。至于其余的数据库产品,不在讨论之列。
Oracle数据库的数据块(Data Block)结构及相关特性
(参照:http://docs.oracle.com/cd/B28359_01/server.111/b28318/logical.htm)
数据块格式
公共和变量块头( Common and Variable Header)
DB2数据库的数据页(Data Page)结构及相关特性
数据页格式
在标准表中,数据在逻辑上按数据页的列表进行组织。这些数据页根据表空间的Extent大小在逻辑上分组到一块儿。这个Extent组相似于Oracle中的Segment,但Extent组没有Segment那样的强制概念。
每一个数据页都具备相同的格式。每一页的最前面都是页头,后面跟着槽(Slot)目录,而后是可用空间和记录。
页头(Header)
用于存放BPS HEADER和一些页的信息字段,其中BPS HEADER占48字节,整个页头大概占91个字节。
槽目录(Slot Directory)
槽目录相似Oracle的数据块中的行目录,槽目录中的每一个条目都与该页中的一个记录相对应。槽目录中的条目表明记录开始位置在数据页中的字节偏移。值为 -1 的条目与已删除的记录相对应。
可用空间(Free Space)
DB2可用空间严格来讲包括一般意义上的常规可用空间和嵌入的可用空间。其中常规可用空间可用直接存储数据,而嵌入的可用空间一般是记录被删除后产生的碎片空间,不能直接使用,只有当页重组后合并到常规可用空间后才能被使用,这一点和Oracle相似。
记录(Record)
已经存储了数据的空间,相似于Oracle中的行数据。即表中的行存放于页面中成为记录。根据数据页大小以及记录大小的不一样,每一个数据页中包含的记录数(即行数据数)也会有所变化。大多数页仅包含用户记录(即普通的数据库数据)。可是,少数页包含由数据服务器用于管理表的特殊内部记录。例如,在标准表中,每 500 个数据页就有一个可用空间控制记录(FSCR)。这些记录用于映射后续每 500 个数据页(直到下一个 FSCR 为止)中可供新记录使用的可用空间。另外,在DB2 V9以前,每一个数据页最多能够存放255条记录,而DB2 V9以后,每一个数据页理论上能够存放65000条记录(与RID有关,暂不讨论),但实际上受限于数据页大小,每一个数据页大概能存放2300多条记录。
行连接和行迁移
DB2是不容许行(记录)跨页的,即不容许行连接。可是容许行迁移(DB2中又称为行溢出),
当表中存在变长数据类型时,容易发生行溢出现象,行溢出有时也叫行迁移,它表示当咱们更新变长数据类型的字段时,因为更新的数据长度比原数据长,以致于当前的数据页没法存放整行数据时,就须要把这行数据存放到一个新的数据页,并在原来的数据页内存放该行新位置的指针以指向新行位置,被移动的数据的RID(RID之后讨论)保持不变。显然,若是大规模出现行迁移的现象,那么必然会对数据库访问的效率产生严重影响(I/O大幅增长),若是表中发现大量行迁移现象,建议进行重组(REORG)操做,从新规划数据存储位置消除行溢出。
对应DB2数据页还须要强调的一点是:DB2的数据页和Oracle数据块同样,也有PCTFREE和PCTUSED的概念,其含义与做用也大体相同,不赘述。
另外能够看到,Oracle的数据块结构和DB2的数据页结构是很是类似的。还有一点,两者的行数据都是从高位开始向低位写,而行目录则是由低位向高位写,为何要这样呢?由于数据的插入是一个两头写的过程,既要将数据写入到可用空间中成为行数据或记录,又要更新头部后面的行目录或槽目录,若是同侧写不利于空间的扩展。下图是一个直观图:
数据行结构
如今对数据块(页)的具体结构已经有了一个大概的了解,那么表中的一行数据是怎样以行数据(记录)的形式保存在数据块(页)中的呢?这个问题看似简单,实际上,一个数据行(记录,即上图中的Row)的结构是很是复杂的,这里以DB2中数据行的结构为例。如图:
各参数解释以下:
能够看到,当元组(即表中的行)中存在变长列的时候,无论该列位于什么位置,在数据行(记录)中都被挪到最后面存储,而定长列则顺序存储。
【注:表的属性列在定义的时候指定了数据类型,有的数据类型是变长的,好比varchar,其大小随实际值的变化而变化,有的列数据类型的定长的,好比int为32位,物理该列上的实际值是多少,都占用4个字节。一旦列中出现变长数据类型的列,则该元组为变长元组。】
下图是状态位A的每一位的含义(1个字节=8位),状态位B是未使用的。
下面看看一个定长的元组(行)在数据行(记录)中具体是如何存放的:
有些复杂,将此图与前面贴的结构图对照着看。【注意:全部数据在数据页的数据行(记录)中都是以十六进制存放的,且为逆序存放】
下面是变长的元组(行)在数据行(记录)中具体存放方式,与定长元组的存放方式大同小异:
对于含大对象数据类型的元组,其大对象数据并不与数据行存放在一块儿,而是与数据行分开放置于数据库的不一样页中,在该元组(行)的数据行中存放一个指向该大对象的指针。如图:
以上就是数据库系统磁盘存储内部结构的大体内容了
https://blog.csdn.net/u011537073/article/details/49157903 ,若有侵权,请联系 linjie.rd@gmail.com 删除