1.1 页和区
1.1.1 文件类型
SQL Server 的文件存储主要有以下 3 种类型:
(1)数据文件
数据库的主要数据就保存在数据文件中,SQL Server有专门的存储引擎用于管理这些文件中的数据。
(2)文件流
对于某些非结构化的数据(例如文档和图像),如果使用 SQL Server 的 image 或者 varbinary(max) 数据类型来存储和管理,将带来诸多不便,其中比较突出的问题在于读取效率比较低。
SQL Server 2008 引入了文件流(FileStream),从而将数据库系统与 Windows 文件系统进行了结合,非结构化数据以二进制方式存放在 Windows 文件系统中,而数据库中存储的是文件系统的指针等相关信息,并且可以由数据库进行统一管理(例如备份和还原)。
(3)日志文件
日志文件用于存储数据库工作中产生的事务日志。
1.1.2 数据页的基本结构
数据文件的基本存储是以“页”(Page)为单位。每一个页为 8KB(8192 字节)。页是 SQL Server 可以读写的最小 I/O 单位,也就是说,即使只需要读取非常简单的一个数据行,SQL Server 也必须读取该数据行所在的整个页。
数据页用于保存表、索引的数据(行)。每个数据页都由标头、数据行、保留区这三个部分组成。
(1)标头
每一个数据页都包含一个96字节的标头。例如,SQL Server 2008 使用了其中64字节,其他32字节作为保留。标头包含的信息如下表所示。
字节顺序 | 包含的信息 |
此页面在数据库中的PageId,包括所属的物理文件ID及页面编号 | |
下一个PageId(如果此页面属于一个页面链) | |
上一个PageId(如果此页面属于一个页面链) | |
此页面所属的数据库对象的ObjectId | |
此页面所属的分区的PartitionId | |
包含此页面的分配单元的AllocUnitId | |
用于修改和更新此页面的事务 LSN | |
此页面上已有的记录(slot)的总数 | |
此页面在索引中的层级 |
此页面在所属的索引的 IndexId | |
此页面上第一块空闲空间的字节偏移量 | |
记录的定长部分的总字节数 | |
此页面上的空闲的总字节数 | |
所有事务保留的字节数 | |
最新开始的事务保留的字节数 | |
残缺页检测 | |
包含页面其他信息的位图(2字节) | |
(2)数据行
数据行紧跟在标头之后,数据行的最大长度是8060字节。由于数据行不能“跨页”,因此单行数据最多8060字节,但对于可变长对象与LOB对象有特殊的处理方法从而可以“跨页”。
实际上,每一行的数据内容最多不能超过8053,因为 SQL Server 还需要对每一行的数据最少附加7字节的系统数据。
(3)保留区
位于页的末尾的是行偏移矩阵,或称为行偏移数组,或行指针,它最少占用36字节。
每一行记录都对应一个条目块(Entity Block),条目块的编号分别为 slot0、slot1、slot2 等。每个条目块由2个字节构成,记录该行记录的第一个字节与页首的距离。行偏移矩阵只表示了本页所有数据行的逻辑顺序,而且条目顺序与数据行的顺序相反,即页的最后2个字节为 slot0,倒数第3个和第4个字节为 slot1,依此类推。
行的物理位置可以是页面上的任意位置。如果是聚集表,slot0 引用聚集索引键顺序中的第一行,slot1 引用第二行,依此类推。
行偏移矩阵最少为36字节,因此默认最多只可以记录18个数据行。当该页超过18条记录时,系统将动态缩减数据行占用的字节数,但数据行与行偏移矩阵总共保持8096字节。
1.1.3 行数据的存储结构
SQL Server 有以下3种类型的页面来存储行数据。
(1)行内数据(IN_ROW_DATA)的页面
在旧版本的 SQL Server 中,每一个记录行都不能跨页,而且被限制为 8060 字节(Text、Image类型的LOB除外),还要考虑留有足够的空间存储行偏移矩阵的条目块。
(2)行溢出数据(ROW_OVERFLOW_DATA)的页面
SQL Server 2005 及后续产品对于含有varchar(旧版本为text)、nvarchar(旧版本为ntext)、varbinary(旧版本为image)、SQL_Variant 以及 CLR 用户定义类型的数据行,可以超过这一限制。当记录行超过8060字节时,这些类型的值将被移动到一个“行溢出分配单元”的页中,并且在原始页中保留一个24字节的指针用于指向行外的页。这样就实现了行可以跨页的功能,但行内的数据仍然被限制为8060字节。
(3)LOB数据(LOB_DATA)的页面
如果需要“溢出”的数据的大小不超过8000字节时,“溢出”的数据将被移动到行溢出页中。如果数据的大小超过了8000字节,这些值将被内部处理为一个“大型对象”(large object,缩写为LOB),而在原始行上维护一个16字节的指针,指向该LOB。
1.1.4 区
区(Extent),也称为扩展,或盘区,是8个物理上连续的页组成的单元,即64KB的空间,用于存储表和索引。 SQL Server 有两种类型的区:
(1)统一区(Uniform Extent)
统一区由单个对象拥有,只有该对象可以使用该区中的8个页面。当表或索引需要更多的空间以存储数据时,SQL Server为对象分配一个完整的区。
(2)混合区(Mixed Extent)
由于每个页面可由一个对象拥有,因此一个混合区最多可由8个对象拥有。对于包含少量数据的对象且不足64KB时,当它需要更多空间时,SQL Server通常只分配一个单独的页,而不是整个区。这个页可以位于一个混合区内。
由于I/O负载多数消耗在磁盘寻址方面,因此读取一个连续8个页面的区,与读取一个页,所用的时间几乎一样多。SQL Server对一些大型表或索引的扫描,可以在区级别上读取数据,大多数情况下都可以提升性能。
本文出自 “SQL Server 管理员指南” 博客,谢绝转载!