页是SQL Server 中数据存储的基本单位,为数据库中的数据文件(mdf、ndf)分配的磁盘空间可以逻辑上划分为页(0-n连续编号),日志文件不包含页,而是包含一系列日志记录。磁盘I/O操作在页级执行。也就是说SQLServer读取或写入所有的数据页;页的大小为8KB
区是由8个物理上连续的页构成的集合,区有助于有效管理页。
在数据页上,数据行紧接着标头按顺序放置。页的末尾是行偏移表,对于页中的每一行,每个行偏移表都包含一个条目。每个条目记录对应行的第一个字节与页首的距离。行偏移表中的条目的顺序与页中行的顺序相反。
大型行支持
行不能跨页,但是行的部分可以移出行所在的页,因此行实际可能非常大。页的单个行中的最大数据量和开销是 8,060 字节 (8 KB)。但是,这不包括用 Text/Image 页类型存储的数据。包含 varchar、nvarchar、varbinary 或 sql_variant 列的表不受此限制的约束。当表中的所有固定列和可变列的行的总大小超过限制的 8,060 字节时,SQL Server 将从最大长度的列开始动态将一个或多个可变长度列移动到ROW_OVERFLOW_DATA 分配单元中的页。每当插入或更新操作将行的总大小增大到超过限制的 8,060字节时,将会执行此操作。将列移动到 ROW_OVERFLOW_DATA 分配单元中的页后,将在 IN_ROW_DATA 分配单元中的原始页上维护 24 字节的指针。如果后续操作减小了行的大小,SQL Server 会动态将列移回到原始数据页
SQLServer 是用两种类型的分配映射表来记录区的分配
全局分配映射表(GAM)
GAM 页记录已分配的区。每个 GAM 包含 64,000 个区,相当于近 4 GB 的数据。GAM 用 一 个位来表示所涵盖区间内的每个区的状态。如果位为 1,则区可用;如果位为 0,则区已分配。
共享全局分配映射表(SGAM)
SGAM 页记录当前用作混合区且至少有一个未使用的页的区。每个 SGAM 包含 64,000 个区,相当于近 4 GB 的数据。SGAM 用一个位来表示所涵盖区间内的每个区的状态。如果位为 1,则区正用作混合区且有可用页。如果位为 0,则区未用作混合区,或者虽然用作混合区但其所有页均在使用中。
页可用空间(PFS)
记录每页的分配状态,是否分配单个页以及每个月的可用空间量。PFS对每个月都有一个字节,用来记录该页是否已分配。如果已分配,则记录该页是为空、已满 1% 到 50%、已满 51% 到 80%、已满 81% 到 95% 还是已满 96% 到 100%。
将区分配给对象后,数据库引擎将使用 PFS 页来记录区中的哪些页已分配或哪些页可用。数据库引擎必须分配新页时,将使用此信息。保留的页中的可用空间量仅用于堆和 Text/Image 页。数据库引擎必须找到一个具有可用空间的页来保存新插入的行时,使用此信息。索引不要求跟踪页的可用空间,因为插入新行的点是由索引键值设置的。
在数据文件中,PFS 页是文件头页之后的第一页(页码为 1)。接着是 GAM 页(页码为 2),然后是SGAM 页(页码为 3)。第一个 PFS 页之后是一个大小大约为 8,000 页的 PFS 页。在第 2页的第一个 GAM 页之后还有另一个 GAM 页(包含 64,000 个区),在第 3 页的第一个 SGAM 页之后也有另一个 SGAM 页(包含 64,000 个区)。下图显示了数据库引擎用来分配和管理区的页顺序。
索引分配映射(IAM)页将映射分配单元使用的数据库文件中4GB部分中的区。
分配单元有三种类型:
1.IN_ROW_DATA(用于存储堆分区活索引分区)
2.LOB_DATA(用于存储大型对象(LOB)数据类型,如XML、VARBINARY(MAX)和VARCHAR(MAX))
3.ROW_OVERFLOW_DATA(用于存储超过8060字节行大小限制的varchar、nvarchar、varbinary或sql_variant列找那个存储的可变长度数据)
堆或索引的每个分区至少包含一个 IN_ROW_DATA 分配单元。根据堆或索引的架构,可能还包含一个 LOB_DATA 或 ROW_OVERFLOW_DATA 分配单元。有关分配单元的详细信息,请参阅表组织和索引组织。
一个IAM 页在文件中的范围为 4 GB,与 GAM 或 SGAM 页的范围相同。如果分配单元包含来自多个文件的区,或者超过一个文件的 4 GB范围,那么一个 IAM 链中将链接多个 IAM 页。因此,每个分配单元在有区的每个文件中至少有一个 IAM 页。如果分配给分配单元的文件中的区的范围超过了一个 IAM 页能够记录的范围,一个文件中也可能会有多个 IAM 页。
IAM 页根据需要分配给每个分配单元,在文件中的位置也是随机的。系统视图 (sys.system_internals_allocation_units) 指向分配单元的第一个 IAM 页。该分配单元的所有 IAM 页都链接到一个链中。
重要提示: |
sys.system_internals_allocation_units系统视图仅供内部使用,随时可能更改。不保证兼容性。 |
IAM 页有一个标头,指明 IAM 页所映射的区范围的起始区。IAM 页中还有一个大位图,其中每个位代表一个区。位图中的第一个位代表范围内的第一个区,第二个位代表第二个区,依此类推。如果某个位是 0,它所代表的区将不会分配给拥有该 IAM 页的分配单元。如果这个位是 1,它所代表的区将被分配给拥有该 IAM 页的分配单元。
当SQL Server 数据库引擎必须在当前页中插入新行,而当前页中没有可用空间时,它将使用 IAM 和 PFS 页查找要将该行分配到的页,或者(对于堆或Text/Image 页)查找具有足够空间容纳该行的页。数据库引擎使用 IAM 页查找分配给分配单元的区。对于每个区,数据库引擎将搜索 PFS 页,以查看是否有可用的页。每个 IAM 和 PFS 页覆盖大量数据页,因此一个数据库内只有很少的 IAM 和 PFS 页。这意味着 IAM 和 PFS 页通常位于内存中的 SQL Server 缓冲池中,所以能够很快找到它们。对于索引,新行的插入点由索引键设置。在这种情况下,不会出现上述搜索过程。
仅当 数据库引擎不能在现有的区中快速找到足以容纳插入行的页时,才将新区分配给分配单元。数据库引擎使用比例分配算法从文件组的可用区中分配区。如果文件组内有两个文件,而一个文件的可用空间是另一个文件的两倍,那么每从后一个文件分配一页,就从前一个文件分配两页。这意味着文件组内的每个文件应该有近似的空间使用百分比。
SQLserver使用两个内部数据结构跟踪被大容量复制操作修改的区,以及自上次完整备份后修改的区:
1.DCM(差异更改映射表)
这样便可以跟踪自上次执行 BACKUP DATABASE 语句后更改过的区。如果扩展盘区的位是 1,则自上次执行 BACKUP DATABASE 语句后扩展盘区已被修改。如果位是 0,则扩展盘区没有被修改。
差异备份只读取 DCM 页便可以确定已修改的区。这样大大减少了差异备份必须扫描的页数。运行差异备份所需的时间与自上次执行 BACKUP DATABASE 语句之后修改的区数成正比,而不是与整个数据库的大小成正比。
2.BCM(大容量更改映射表)
跟踪自上次执行 BACKUP LOG 语句后,被大容量日志记录操作修改的区。如果某个扩展盘区的位是 1,表明自上次执行 BACKUP LOG 语句后,该扩展盘区已经被有日志记录的大容量复制操作修改。如果位是0,则该扩展盘区未被有日志记录的大容量复制操作修改。
尽管所有数据库中都显示 BCM 页,但只有在数据库使用大容量日志记录恢复模式时,才会与 BCM 页有关。在此恢复模式中,当执行 BACKUP LOG 时,备份进程将扫描 BCM 查找已经修改的区。然后,将那些区包括在日志备份中。如果数据库从数据库备份和一系列事务日志备份恢复,便可以恢复大容量日志记录操作。在使用简单恢复模式的数据库中,BCM 页是不相关的,因为大容量日志记录操作不记入日志。在使用完整恢复模式的数据库中,BCM页同样不相关,因为该恢复模式将大容量日志记录操作视为有完整日志记录的操作。
DCM 页和 BCM 页的间隔与 GAM 和SGAM 页的间隔相同,都是 64,000 个区。在物理文件中,DCM 和 BCM 页位于 GAM 和 SGAM 页之后。
SQLServer 数据文件中的页(数据文件页)按顺序编号,文件的首页以 0 开始。数据库中的每个文件都有一个唯一的文件 ID 号。若要唯一标识数据库中的页,需要同时使用文件 ID 和页码。下例显示了包含 4-MB 主数据文件和 1-MB 次要数据文件的数据库中的页码。
每个文件的第一页是一个包含有关文件属性信息的文件的页首页。在文件开始处的其他几页也包含系统信息(例如分配映射)。有一个存储在主数据文件和第一个日志文件中的系统页是包含数据库属性信息的数据库引导页。