数据库中的空间分为逻辑8KB页面。这些页面从开始连续编号并且可以通过指定文件标识和页码来引用它们。页码是总是连续的,这样当数据库文件增长时,新的页面从开始编号从文件中最高的页码加一。同样,当SQL Server收缩文件时,它会删除文件中的最高页数。
SQL SERVER中的数据存储
一般来说,有三种不同的方法或技术来存储和处理数据库中的数据。对于传统的基于行的存储,数据存储在数据行中将所有列中的数据组合在一起。
SQL Server 2012引入了列存储索引和基于列的存储。这项技术可以储存基于每列而不是每行的数据。我们将在的第七部分介绍基于列的存储。
最后,我们在2014年推出了一套内存技术,并对其进行了进一步改进在SQL Server 2016中。即使它们出于冗余目的将数据保存在磁盘上,它们的存储格式与基于行和基于列的存储非常不同。我们将讨论记忆本书第八部分中的技术。
本书的这一部分着重于基于行的存储以及经典的B树索引和堆
图1-6显示了数据页面的结构。
图1-6数据页面结构
一个96字节的页面标题包含关于页面的各种信息,例如页面所属、页面上可用的行数和可用空间量、指向上一页的链接和下一页(如果该页在索引页链中),依此类推。
页眉后面是存储实际数据的区域。接下来是自由空间。最后,有一个插槽数组,它是一个由两字节条目组成的块,指示相应数据的偏移量行从页面开始。
插槽数组指示页面上数据行的逻辑顺序。如果页面上的数据需要按照索引键的顺序排序,SQL Server不会对页面上的数据行进行物理排序,而是它根据索引排序顺序填充插槽数组。插槽0(图1-6中最右边)存储了的偏移量页面上具有最低键值的数据行;槽1,第二低的键值;等等我们会在下一章中更深入地讨论索引。
SQL Server提供了一组丰富的系统数据类型,这些数据类型可以在逻辑上分为两种不同的类型
组:固定长度和可变长度。固定长度的数据类型,如int、datetime、char等,始终使用相同数量的存储空间,无论其值如何,即使它为空。例如,int列总是使用4字节,nchar(10)列总是使用20字节来存储信息。
相比之下,可变长度的数据类型,如varchar、varbinary和其他一些类型,使用的也一样多
存储数据所需的存储空间,外加两个额外字节。例如,nvarchar(4000)列将仅使用12个字节来存储五个字符串,在大多数情况下,使用两个字节来存储空值。稍后,我们将讨论可变长度列不为空值使用存储空间的情况。
让我们看看数据行的结构,如图1-7所示
图1-7数据行结构
行的前两个字节称为状态位A和状态位B,是包含信息的位图关于该行,例如行类型,如果该行已被逻辑删除(备份),并且如果该行为空值、可变长度列和版本标记。
行中接下来的两个字节用于存储数据的固定长度部分的长度。她们后面跟着固定长度的数据本身。
在固定长度的数据部分之后,有一个空位图,它包括两个不同的数据元素。第一个双字节元素是行中的列数。第二个是空位图数组。这个数组对表中的每一列使用一位,不管它是否可为空。
空位图总是出现在堆表或聚集索引叶行的数据行中,即使表没有可为null的列。但是,空位图不在非叶索引行中,也不在当索引中没有可空列时,非聚集索引的叶级行。
在空位图之后,是行的可变长度数据部分。它以两个字节开始行中后跟列偏移数组的可变长度列数。SQL Server存储两个字节行中每个可变长度列的偏移值,即使该值为空。接下来是数据的实际可变长度部分。最后,最后还有一个可选的14字节版本标签排在第一位。此标记用于需要行版本控制的操作,例如在线索引重建,乐观的隔离水平、触发因素和其他一些因素。
■注意:我们将在第6章讨论索引维护,在第9章讨论触发器,以及乐观隔离级别在第21章。
让我们创建一个表,用一些数据填充它,并查看实际的行数据。代码如清单1-4所示,复制功能将作为第一个参数提供的字符重复十次。
清单1-4,数据行格式:表创建
一个未记录但众所周知的DBCC IND命令返回关于表页的信息拨款。您可以在图1-8中看到这个命令的输出。
图1-8,DBCC工业发展局产出
这张桌子有两页。第一个页面类型为10,是一种特殊类型的页面称为IAM分配图。此页面跟踪属于特定对象的页面。然而,现在我们将在本章后面介绍分配图页面。
■注意:SQL Server 2012引入了另一个未记录的数据管理功能database_page_allocations,可用作DBCC IND命令的替换。的产量与DBCC工业发展局相比,该车管局提供了更多信息,可以与其他系统车管局结合使用和/或目录视图。
页面类型=1的页面是包含数据行的实际数据页面。页面文件和
页面PID列显示页面的实际文件和页码。您可以使用另一个未记录的
命令来检查它的内容,如清单1-5所示。页面类型=1的页面是包含数据行的实际数据页面。页面文件和页面PID列显示页面的实际文件和页码。您可以使用另一个未记录的命令来检查它的内容,如清单1-5所示。
清单1-5,数据行格式:DBCC页面调用
清单1-6显示了对应于第一个数据行的DBCC页面的输出。SQL Server存储按字节交换顺序的数据。例如,两字节值0001将存储为0100。
清单1-6,第一行的DBCC页面输出
让我们更详细地看看数据行,如图1-9所示。
图1-9,第一个数据行
如您所见,该行以两个状态位开始,后跟一个双字节值0800。这是字节交换值0008,是行中列数属性的偏移量。这个偏移量告诉SQL Server行的固定长度数据部分在哪里结束。
接下来的四个字节用于存储固定长度的数据,在我们的例子中,这是标识列。在那之后,有两个字节的值显示数据行有四列,后跟一个字节的空值位图。只有四列,位图中的一个字节就足够了。它存储04的值,即00000100以二进制格式。它指示行中的第三列包含空值。接下来的两个字节存储行中可变长度列的数量,即3 ( 0300字节)订单。其后是一个偏移量数组,其中每两个字节存储一个偏移量,变量长度为列数据结束。如您所见,即使列2为空,它仍然使用偏移数组中的槽。最后,还有来自可变长度列的实际数据。
现在,让我们看看第二个数据行。清单1-7显示了DBCC页面输出,图1-10显示的行数据。
图1-10,第二数据行数据
清单1-7,第二行的DBCC页面输出
第二行中的空位图表示二进制值00001010,它显示列1和列3为空。即使表有三个可变长度列,可变长度的数量行中的列表示偏移数组中只有两列/插槽。SQL Server不支持维护行中尾随空变长列的信息。
■提示您可以通过以可变长度的方式创建表格来减小数据行的大小通常存储空值的列被定义为CREATE TABLE语句中的最后一列。这是CREATE TABLE语句中列的顺序唯一重要的情况。
固定长度的数据和内部属性必须适合单个数据页上可用的8,060字节。当情况并非如此时,SQL Server不允许您创建该表。例如,清单1-8中的代码产生错误。
清单1-8,创建数据行大小超过8,060字节的表、