我已经创建了下表:
CREATE TABLE dbo.TestStructure
(
id INT NOT NULL,
filler1 CHAR(36) NOT NULL,
filler2 CHAR(216) NOT NULL
);
然后创建一个聚集索引:
CREATE CLUSTERED INDEX idx_cl_id
ON dbo.TestStructure(id);
接下来,我为它填充30行,每个行的大小为256字节(基于表声明):
DECLARE @i AS int = 0;
WHILE @i < 30
BEGIN
SET @i = @i + 1;
INSERT INTO dbo.TestStructure (id, filler1, filler2)
VALUES (@i, 'a', 'b');
END;
现在,根据我在“培训工具包(考试70-461):查询Microsoft SQL Server 2012(Itzik Ben-Gan)”书中阅读的信息:
SQL Server在内部将数据组织在页面中的数据文件中。页面是一个8 KB的单元,属于一个对象。例如,到表或索引。页面是最小的读写单位。页面被进一步组织为扩展区。范围由八个连续的页面组成。扩展区中的页面可以属于单个对象,也可以属于多个对象。如果页面属于多个对象,则该范围称为混合范围;如果页面属于单个对象,则范围称为统一范围。SQL Server在混合范围中存储对象的前八页。当对象超过八页时,SQL Server会为此对象分配其他统一范围。通过这种组织,小物体浪费更少的空间,大物体的碎片也更少。
因此,这里有第一个混合扩展区8KB页面,其中填充了7680个字节(我已插入30次256字节大小的行,所以30 * 256 = 7680),以检查我运行大小检查proc的大小-它返回以下结果
index_type_desc: CLUSTERED INDEX
index_depth: 1
index_level: 0
page_count: 1
record_count: 30
avg_page_space_used_in_percent: 98.1961947121324
name : TestStructure
rows : 30
reserved : 16 KB
data : 8 KB
index_size : 8 KB
unused : 0 KB
因此,为该表保留了16 KB,第一个8 KB页面用于Root IAM页面,第二个页面用于叶子数据存储页面,该页面为8KB,占用空间约为7.5 KB,现在我插入一个256字节的新行时:
INSERT INTO dbo.TestStructure (id, filler1, filler2)
VALUES (1, 'a', 'b');
尽管它有256字节的空间(7680 b + 256 = 7936,仍然小于8KB),但它没有存储在同一页上,创建了一个新的数据页,但是该新行可以放在同一旧页上,为什么SQL Server在可以节省空间和搜索时间的情况下(如果将其插入到现有页面中)会创建一个新页面?
注意:堆索引中发生了相同的事情。