3.1 数据库物理存储结构
数据库管理系统体系结构最底层的管理器从原理上讲都可以统称为磁盘空间管理器,所以,数据库的物理存储是指数据库的数据以什么方式存储在计算机磁盘上,又是怎么在磁盘空间管理器管理下运行的。
3.1.1 数据库文件和文件组
数据库在磁盘上是以文件为单位存储的,由数据库文件和事务日志文件组成,一个数据库至少应该包含一个数据库文件和一个事务日志文件,有时可能还包括次要文件和多个事务日志文件。
- 主数据库文件(Primary Database File):是数据库的起点,可以指向数据库中文件的其他部分。每个数据库都有一个主数据库文件。文件扩展名一般是.mdf。
- 次数据库文件(Secondary Database File):有些数据库可能没有次数据文件,而有的数据库则有多个次数据文件。文件扩展名多是.ndf。
- 事务日志文件:日志文件包含恢复数据库所需的所有日志信息。每个数据库必须至少有一个日志文件,但可以不止一个。推荐的文件扩展名是.ldf。
图3-1所示为在SQL Server 2005默认实例上按默认存储位置创建的数据库文件示例,它有一个主数据库文件、两个次数据库文件和两个日志文件。
图3-1 创建的数据库文件存储
为了便于分配和管理,SQL Server允许将多个文件归纳为同一组,并赋予此组一个名称,这就是文件组。文件组能够控制各个文件的存放位置,其中的文件常建立在不同的硬盘驱动器上,这样可以减轻单个磁盘驱动器的存储负载,提高数据库的存储效率,从而达到提高系统性能的目的。
在存储数据时,SQL Server采用按比例填充的策略使用文件组内每个文件所提供的存储空间。例如,如果一个服务器上有4个可供数据库使用的硬盘,提供给数据库的最大存储空间分别为100 MB、200 MB、300 MB和100 MB,我们可以在前面3个硬盘上建立一个数据文件组,包含3个文件,每个硬盘上分配1个文件,在第4个硬盘上建立数据库的日志文件,当发生数据库的读写操作时,日志数据写入第4个硬盘,而数据库数据写入前3个硬盘。在写入数据时,SQL Server根据文件组内每个数据文件中剩余的空间大小按比例分配写入其中的数据量,即1:2:3。这样不仅保证文件组内每个文件的空间基本上同时用完,而且将一次磁盘操作同时分配给多个磁盘控制器,可以减轻每个磁盘的负载,从而提高写入速度。
在SQL Server中建立数据文件和文件组时,应注意以下两点:
①每个数据文件或文件组只能属于一个数据库,每个数据文件也只能成为一个文件组的成员。也就是说,数据文件不能跨文件组使用,数据文件和文件组不能跨数据库使用。
②日志文件是独立的,它不能作为其他数据文件组的成员。即数据库内的数据和日志不能存入相同的文件或文件组。
与数据库文件一样,文件组也分为主文件组(Primary File Group)和次文件组(Secondary File Group)。
①主文件组:包含主数据文件和所有未被包含在其他文件组里的文件。在创建数据库时,如果未指定其他数据文件所属文件组,这些文件将归属于主文件组。数据库的系统表都包含在主文件组中,所以,当主文件组的空间用完后,将无法向系统表中添加新的目录信息。
②次文件组:也称用户自定义文件组,包括所有使用数据库创建语句(CREATE DATABASES)或数据库修改语句(ALTER DATABASES)时使用FILEGROUP关键字指定的文件。
任何时候,只能有一个文件组是默认文件组。默认情况下,主文件组被认为是默认文件组。
使用数据文件和文件组应注意以下几点。
①创建数据库时,允许数据文件能够自动增长,但要设置一个上限,否则有可能充满磁盘。
②主文件组要足够大以容纳所有的系统表,否则新的信息就无法添加到系统表中,数据库也就无法追加修改。
③建议把频繁查询的文件和频繁修改的文件分放在不同的文件组中。
④把索引、大型的文本文件和图像文件放到专门的文件组中。
3.1.2 数据文件的使用分配
1.基本知识
数据库管理系统体系结构底层的这些管理器,从原理上讲都可以统称为磁盘空间管理器,磁盘空间管理器支持作为数据单元的页的概念,并且提供分配、回收页和读写页的命令。通常以磁盘块的大小作为页的大小,并且将页以磁盘块的方式存储起来,以便在一次磁盘I\O中就能完成一页的读写。
为一连串的页分配连续的磁盘块来存放那些需要频繁地按顺序访问的数据是非常有用的。对发挥顺序访问磁盘块的优势来说,这种能力是必需的。如果有必要,这种能力也可以由磁盘空间管理器提供。
总之,磁盘空间管理器隐藏了底层硬件和操作系统的细节,并允许数据库管理系统的高层软件把数据看成是页的集合。因此,在SQL Server 2005的体系结构中有专门的页管理器和文本管理器。
在SQL Server 2005中,数据文件存储的基本单位是页,页的大小是8 KB。这就意味着SQL Server 2005数据库每兆字节有128页。每页的开始部分是96字节的页首,用于存储系统信息,如页的类型、页的可用空间量、拥有页的对象ID等。根据页面所存储的不同信息,可以将它划分为8种类型
表3-1所示为SQL Server 2005数据库的数据文件中的8种页类型。
表3-1 SQL Server 2005数据文件中的页类型
2.数据页面存储格式
(1)数据页面
SQL Server 2005中,数据文件的页按顺序编号,这个编号称为页码。文件首页的页码是0。众多数据页构成一个数据文件,每个数据文件都有一个文件ID号。在数据库中唯一标识的一页需要同时使用文件ID和页码。
图3-2 数据页面的存储结构
数据页中数据由数据行组成,数据行中包含除TEXT、NTEXT和IMAGE数据外的所有数据,TEXT、NTEXT和IMAGE数据存储在单独的页中。在数据页上,数据行紧接着页首按顺序放置。在页尾有一个行偏移表。页上的每一行在行偏移表中都有一个条目,每个条目记录对应行的第1字节与页首的距离。行偏移表中的条目序列与页中行的序列相反。数据页面的存储结构如图3-2所示。
页首占用每个数据页的前96字节,剩余的8096字节用于数据和行偏移数组。
(2)数据行
紧跟着页头的就是存储表的真正数据行区域。单个数据行的最大长度是8060字节。
数据行不能跨页存储(文本和图像例外)。页内数据行的多少依赖于表的结构和要存储的数据。
如果一个表的所有列都是定长的,那么该表在每一页上存储相同数目的行。
如果一个表中有变长列,那么该表总是在每一页上存储尽可能多的行。
数据行越短,每一页存储的行数就越多。
(3)行偏移表
当单行数据长度为最大8060字节时,行偏移表占用8096 − 8060 = 36字节。
但实际中一个数据行大多不是8060字节,往往比这个数字小,所以数据行占用的总字节数目和行偏移表占用的总字节数是系统动态调整的,数据行字节越少,行偏移表字节越多,反之,数据行字节越多,行偏移表字节越少,但不能少于36字节。
每两个字节构成一个条目块,每个条目表示页中相关数据行第1字节相对页首的偏移量。
注意:行偏移数组表示的是页中数据行的逻辑顺序,不是物理顺序。真正的物理顺序与聚集索引有关。
(4)页面链接
每个表或索引视图的数据行一般都分开存储在多个8 KB数据页中。如上所述,每个数据页都有一个96字节的页头,其中包含拥有该页的表的标志符(ID)这样的系统信息,也包含指向下一页及前面用过的页的指针,如图3-3所示。
图3-3 页面链接
3.SQL Server空间使用分配
SQL Server 2005数据库是存储表和索引的,向表或索引分配空间的基本单位为区域,一个区域长度为8个连续的页面,也就是64 KB。区域分为以下两种类型。
①统一区域:区域中的8个页面只能存储同一种数据库对象。
②混合区域:区域中不同页面可以存储不同的数据库对象。1个混合区域最多可以存储8种数据库对象。
SQL Server对空间使用分配时,当数据库对象中的数据较少时,可以分配混合区域,供数据库中不同类型的数据库对象使用。但当同种数据库对象所占用的空间达到8个页面时,可以再将它们转换为统一区域。
SQL Server使用以下两种类型的分配映射页面记录区域的分配使用情况。
①全局分配映射(Global Allocation Map,GAM)页面:GAM页面用来记录哪些区域已经作为何种类型的区域分配使用。该页面中的每一位记录一个区域的分配情况,当位值为1时,说明区域为空闲区域,当位值为0时,表示区域已经被分配使用。由于每个页面大小为8 KB,所以一个GAM页面能够覆盖64 000个区域,即4 GB。
②共享全局分配映射(Shared Global Allocation Map,SGAM)页面:SGAM页面用于记录有空闲页面的混合区域,而且至少有一页未被使用。每个SGAM页面覆盖64 000个区域。当位值为1时,说明区域为混合区域,并且其中有空闲页面;当位值为0时,说明相应的盘区未被用做混合区域,或者它是一个没有空闲页可分配的混合区域。
表3-2 区域在GAM和SGAM页面中的位值设置
表3-2说明了区域可能的位值设置情况。
SQL Server在分配统一区域时,首先在GAM中查找到一个位值为1的位,然后将其设置为0;而在分配混合区域时,首先在GAM中查找到一个位值为1的位,并将其值设置为0,然后再将SGAM页面中对应位值设置为1。当释放一个区域时,SQL Server将GAM和SGAM页面中的对应位分别设置为1和0。所以如果SQL Server需要找到一个新的、完全未被使用的区域,就可以使用GAM页面中相应位值是1的所有区域;如果SQL Server需要找到一个可用的空间的混合区域,那么GAM页面中对应位值是0,而且SGAM页面中对应位值是1的任何区域就都满足条件。
在任何SQL Server数据库文件中,页面0(即第1页)永远是文件头页面,而且每个文件只能有一个文件头页面存在,页面1(即第2页)是PFS(Page Free Space)页,即页面自由空间页面,第一个GAM页面总是页2(即第3页),之后,每隔64 000个区域就建立另一个GAM或SGAM页面。
4.索引分配映射管理
索引分配映射(IAM)页面管理堆或索引所分配区域的使用情况,它是根据每一个对象的需要来分配的。每个IAM页面的页面头记录该IAM页面所映射区域范围的起始区域,其映射区中的每一位说明一个区域的使用状态,其中第1位代表IAM页面所映射区域范围内的第1个区域,第2位代表第2个区域,等等。当映射区中某位为0时,说明该位所映射的区域仍未分配给拥有该IAM页面的对象使用;当其值为1时,说明该位所映射区域已经分配给拥有该IAM页面的对象使用。
每个堆或索引可以有一个或多个IAM页面记录分配给该对象区域的使用情况,堆或索引在每个分配有区域的数据文件中至少有一个IAM页面。这些IAM页面在数据文件中没有固定的位置,它们根据需要进行分配,并随机定位。一个对象的所有IAM页面组成一个链表,其第一个IAM页面的位置记录在sysindexes系统表的FirstIAM列内。所以,根据FirstIAM列和IAM页面链表就可以查找到一个对象的所有IAM页面。SQL Server确定某个页面属于某个表的唯一方法就是检查该表的IAM页。
5.自由页面及页面空间管理
一旦一个区域分配给某个对象,就可以向这些区域的页中插入数据。如果数据被插入到B树,那么新数据的位置基于它在B树内的顺序,如果数据被插入到堆中,新数据就可以插入到任何有空闲区域的地方。在数据库文件中,SQL Server使用PFS(Page Free Space)页面记录每个单独的页是否已经被分配,以及页面中的空间使用情况,即全部空闲、1%~50%满、51%~80%满、81%~95%满,还是96%~100%满。当SQL Server需要分配新的页面,或者查找到有自由空间页面时,它使用PFS页面中的这些信息。数据库文件的第2页(页面1)是第一个PFS页,其后每经过8088页就又是一个PFS页。
SQL Server使用IAM页面和PFS页面在已经分配的区域内为新插入的数据行查找空闲的页面空间,如果在这些区域内不能查找到足够的空间,它将分配给一个新的区域给数据库对象。
3.1.3 事务日志文件结构
1.事务日志
每个SQL Server数据库都有事务日志,用以记录所有事务和每个事务对数据库所做的修改,目的是一旦数据库出现故障,可以迅速执行前滚、重做等操作,从而保证数据库数据的一致性。为了获得最大的吞吐效果,日志管理器在内存中建立了两个或更多的快速缓冲区,在检索数据时,它将数据读入该缓冲区,而在修改数据时,它并不是直接修改磁盘中的数据,而是先在缓冲区中建立修改数据副本,之后在页面刷新时再将它们写入磁盘。当出现当前日志缓冲区爆满的时候,备用的快速缓冲区就立即启用。每当对缓冲区中的数据页面进行修改时,SQL Server自动在日志缓存中构造该操作的日志记录。每个日志记录由日志序列号所标识(Log Sequence Number,LSN),一个新的日志记录的日志序列号均大于其前面记录的日志序列号,新的日志记录被写在日志的逻辑尾部。
日志记录所记录的操作类型如下:
·每个事务的开始和结束。
·数据的插入、修改和删除操作等。
·事务操作的对象。
·修改前数据的旧值,修改后数据的新值。
·区域的分配和释放。
·表和索引的创建和删除。
在数据库修复阶段所需要的事务日志称做事务日志的有效部分,事务日志有效部分中起始记录的日志序列号叫做最小恢复日志序列号(MinLSN)。MinLSN之前的日志记录对数据库修复操作没有任何用途,但是在数据库日志备份和恢复操作时仍需要事务日志有效部分之前的日志记录,使用它们能够前滚数据库故障点之前的修改内容。
日志记录删除操作称为截断数据库日志。如果一直不截断一个数据库的事务日志,其日志记录最终可能消耗完整个日志文件空间。默认时,在日志备份后,SQL Server会自动删除日志中的不活动部分。
2.事务日志的物理存储
一个数据库事务日志可以对应一个或多个物理文件,SQL Server 2005 在内部又将每个物理日志文件分成许多个虚拟日志文件。虚拟日志文件没有固定大小,且物理日志文件所包含的虚拟日志文件数不固定。在创建或扩展日志文件时,SQL Server 动态地选择虚拟日志文件的大小。虚拟日志文件的大小或数量不能由管理员配置或设置,而由 SQL Server 代码动态确定。
事务日志是回绕的日志文件。例如,假设有一个数据库,它包含一个分成4个虚拟日志文件的物理日志文件。当创建数据库时,逻辑日志文件从物理日志文件的始端开始。在逻辑日志的末端添加新的日志记录,逻辑日志就向物理日志末端增长。截断操作发生时,删除最小恢复日志序号(MinLSN)之前的虚拟日志内的记录,这部分日志记录所占用的空间即可被重复使用。这一过程如图3-4所示。
图3-4 日志记录顺序填充过程
当逻辑日志的末端到达物理日志文件的末端时,新的日志记录绕回物理日志文件的始端,如图3-5所示。这个循环不断重复,只要逻辑日志的末端不到达逻辑日志的始端。如果经常截断旧的日志记录,使得总能为下一个检查点创建的所有新日志记录保留足够的空间,那么日志永远不会填满。然而,如果逻辑日志的末端真的到达了逻辑日志的始端,SQL Server将执行下面两方面的操作:
图3-5 日志记录循环填充过程
①如果对日志启用了自动增长且磁盘上有可用空间,文件就按指定的数量扩展,新的日志记录则添加到扩展的日志文件中。
②如果没有启用自动增长,或者保存日志文件的磁盘上的可用空间比指定的日志文件增长数量少,系统将产生1105个错误。