堆表插入

use*_*729 4 sql-server sql-server-2019

我试图了解 SQL Server 在将记录插入堆表时的行为。根据关于 sql Server博客文章,第 2 段“如果其大小超过页面大小的 20%(8,060 字节 * 0.2 = 1,612 字节),SQL Server 将不会将新行放入页面。

如果我正确理解了该语句,那么如果该表有一个大小为 2025 字节的记录,则第二条记录应该放在另一页上。但是,我的测试并不同意

设置脚本

环境:SQL 2019 x64 开发版。

create table dbo.Heap(id INT, Val varchar(8000) not null);
GO
insert into dbo.heap(ID, val)  values (1,replicate('*',2010));
insert into dbo.heap(ID, val)  values (2,replicate('*',2010));
insert into dbo.heap(ID, val)  values (3,REPLICATE('*',2010));
insert into dbo.heap(ID, val)  values (4,REPLICATE('*',2010));
Run Code Online (Sandbox Code Playgroud)

并运行以下代码

SELECT PARSENAME(REPLACE(REPLACE(REPLACE(CAST(sys.fn_PhysLocFormatter (%%physloc%%) AS varchar),')',''),'(',''),':','.'),2)PageNo,
sys.fn_PhysLocFormatter (%%physloc%%) AS [Location],* FROM heap ORDER BY [ID]
Run Code Online (Sandbox Code Playgroud)

上面的 SELECT 返回如下结果,与 20% page size 的说法不一致。

在此处输入图片说明

我尝试在插入后查看 DBCC PAGE 结果,但 DBCC PAGE 结果没有与插入记录的大小相加。

设置脚本

DROP TABLE IF EXISTS heap
go
create table dbo.Heap(id INT, Val varchar(8000) not null);
GO
insert into dbo.heap(ID, val)  values (1,replicate('*',2010));
go
dbcc traceon(3604);
dbcc page
(
    'demodb' -- Database name
    ,1 -- File ID
    ,416 -- Page ID
    ,1 -- Output mode: 3 - display page header and row details
);
Run Code Online (Sandbox Code Playgroud)

记录大小仅为数据页的 25%,但 PFS 显示 50% 已满,为什么? 在此处输入图片说明 发出第二张插页并查看 PAGE

insert into dbo.heap(ID, val)  values (2,replicate('*',2010));
dbcc page
(
    'demodb' -- Database name
    ,1 -- File ID
    ,416 -- Page ID
    ,1 -- Output mode: 3 - display page header and row details
);
Run Code Online (Sandbox Code Playgroud)

在此处输入图片说明

小智 6

让写这篇博文的人澄清一下:)

你的报价有点断章取义。全文如下:

例如,如果数据页存储 4,100 字节的数据,因此有 3,960 字节的可用空间,PFS 将指示该页已满 51-80%。如果新行的大小超过页面大小的 20%(8,060 字节 * 0.2 = 1,612 字节),则 SQL Server 不会将新行放入页面。

基本上,这意味着如果页面上有80_PCT_FULL标志,SQL Server 会期望该页面最多填充 80% 并且只有 1,612 字节可用。

您的测试证实:

  1. 第一个 INSERT 来到了 416 页。该页被标记为50_PCT_FULL,这意味着它最多可以填充 4,030 个字节。
  2. 2,025 字节的第二个 INSERT 适合同一页。但是,它将使用率推高了 50% 以上,并且页面被标记为80_PCT_FULL,这意味着它可能最多填充 6,448 个字节,并且只有 1,612 个字节是免费保证的。
  3. 第三次插入转到第 417 页,因为您试图插入超过 1,612 个字节

希望这能澄清情况。