Joh*_* N. 5 sql-server sql-server-2008-r2 sql-server-2012 sql-server-2014 sql-server-2017
SQL Server 数据库页的大小定义为 8192 字节。有一些头信息据说大小为 96 字节。
如果您曾经尝试创建一个包含超过 8053 个字节的列定义的表,那么您将看到错误消息:
Run Code Online (Sandbox Code Playgroud)Creating or altering table 'Generated_Data_GUID' failed because the minimum row size would be 8061, including 7 bytes of internal overhead. This exceeds the maximum allowable table row size of 8060 bytes.
以下是一个示例表 DDL:
CREATE TABLE [dbo].[Generated_Data_GUID](
[ID] [int] IDENTITY(1,1) NOT NULL,
[GUID] [uniqueidentifier] NOT NULL,
[SEQGUID] [uniqueidentifier] NOT NULL,
[Data1] [char](4000) NULL,
[Data2] [char](4000) NULL,
[Data3] [char](9) NULL,
[EntryDate] [datetime2](7) NULL
) ON [PRIMARY]
Run Code Online (Sandbox Code Playgroud)
通过以上的DDL如果我改变了列的列定义Data3
是char(10)
,那么我会打的错误消息。
每个列类型的字节大小如下:
int : 4 bytes
uniqueidentifiere : 16 bytes
char(n) : n bytes
datetime2(n) : 6 bytes if n < 3
7 bytes if n = 3 or n = 4
8 bytes if n > 4
Run Code Online (Sandbox Code Playgroud)
如果我们做一些简单的数学运算,那么我们最终会得到以下计算:
Page Size : 8192 bytes
-----------
Header : 96 bytes -
Internal Overhead : 7 bytes -
Max Size : 8053 bytes -
-----------
Missing Data : 36 bytes
===========
Run Code Online (Sandbox Code Playgroud)
这 36 个字节包含什么?
Jos*_*ell 10
Paul Randal 实际上在您链接到的博客文章的评论中回答了这个确切的问题:
8060 字节是一条记录的最大大小,而不是页面上的数据空间量 – 8096 字节。
对于 8060 字节的最大记录,为槽数组条目添加两个字节,为可能的堆转发记录反向指针添加 10 个字节,为可能的版本控制标记添加 14 个字节,即使用了 26 个字节。其他 10 个字节供将来可能使用。
如果页面上有多条记录,则可以使用所有 8096 字节的数据空间。
因此,在回答您帖子正文中的问题时:
这 36 个字节包含什么?
页中“额外”的 36 个字节的用法如下:
只是为了确认问题中定义的表实际上是 8060 字节宽,让我们进行完整的重现。
首先,我们将设置数据库和表,并在其中插入一行。我正在添加一个聚集索引,因为堆是最糟糕的。
USE master;
GO
CREATE DATABASE PageJunk;
GO
USE PageJunk;
GO
CREATE TABLE [dbo].[Generated_Data_GUID](
[ID] [int] IDENTITY(1,1) NOT NULL,
[GUID] [uniqueidentifier] NOT NULL,
[SEQGUID] [uniqueidentifier] NOT NULL,
[Data1] [char](4000) NULL,
[Data2] [char](4000) NULL,
[Data3] [char](9) NULL,
[EntryDate] [datetime2](7) NULL
) ON [PRIMARY];
GO
CREATE CLUSTERED INDEX PK_Generated_Data_GUID
ON Generated_Data_GUID (ID);
GO
INSERT INTO [dbo].[Generated_Data_GUID]
([GUID], SEQGUID, Data1, Data2, Data3, EntryDate)
VALUES
(NEWID(), NEWID(), REPLICATE('1', 4000), REPLICATE('2', 4000), REPLICATE('3', 9), '2018-01-01');
GO
Run Code Online (Sandbox Code Playgroud)
通过运行这个 DBCC 命令,我们可以看到所有分配了索引的页面:
DBCC IND ('PageJunk', 'Generated_Data_GUID', 1);
GO
Run Code Online (Sandbox Code Playgroud)
页类型为 1 的是索引页(页 ID 336)。我们可以使用其他 DBCC 命令转储有关该页面的各种信息:
DBCC TRACEON (3604); -- needed for the next one to work
GO
DBCC PAGE (PageJunk, 1, 336, 3);
GO
Run Code Online (Sandbox Code Playgroud)
以下是该命令输出的一些重要片段。从 HEADER 部分:
m_freeCnt = 34
Run Code Online (Sandbox Code Playgroud)
这意味着页面上有 34 字节的可用空间。这是您在原始帖子中概述的 36,减去插槽数组条目的 2 个字节。说到这:
m_slotCnt = 1
Run Code Online (Sandbox Code Playgroud)
这意味着此页面上只有一条记录。
现在,在记录部分:
Slot 0 Offset 0x60 Length 8060
Record Type = PRIMARY_RECORD Record Attributes = NULL_BITMAP Record Size = 8060
Run Code Online (Sandbox Code Playgroud)
这表明该页上存储的单个记录为 8060 字节(这是所有数据类型存储大小的总和加上每条记录 7 个字节的开销)。
所以我们在这个页面上确实有一个完整大小的 8060 字节记录。但是,如果我们再努力一点,我们仍然可以在此页面上再压缩 34 个字节。
例如,我可以创建一个 2015 字节宽的表。然后每行将占用页面中的 2015 + 7(内部开销)+ 2(槽数组)= 2024 个字节。所以四行加起来应该是 8096 字节,正好填补了 96 字节标头之后剩下的空间。让我们在同一个数据库中试试:
CREATE TABLE [dbo].[QuarterPage](
[ID] [int] IDENTITY(1,1) NOT NULL,
[GUID] [uniqueidentifier] NOT NULL,
[SEQGUID] [uniqueidentifier] NOT NULL,
[Data1] [char](981) NULL,
[Data2] [char](981) NULL,
[Data3] [char](9) NULL,
[EntryDate] [datetime2](7) NULL
) ON [PRIMARY];
GO
CREATE CLUSTERED INDEX PK_QuarterPage
ON QuarterPage (ID);
GO
INSERT INTO [dbo].[QuarterPage]
([GUID], SEQGUID, Data1, Data2, Data3, EntryDate)
VALUES
(NEWID(), NEWID(), REPLICATE('1', 981), REPLICATE('2', 981), REPLICATE('3', 9), '2018-01-01');
GO 4
Run Code Online (Sandbox Code Playgroud)
现在我们找到了我们的页面,只有一个符合预期的:
DBCC IND ('PageJunk', 'QuarterPage', 1);
GO
Run Code Online (Sandbox Code Playgroud)
所以现在我们想要获取第 352 页的信息:
DBCC PAGE (PageJunk, 1, 352, 3);
GO
Run Code Online (Sandbox Code Playgroud)
这是好东西:
m_slotCnt = 4
m_freeCnt = 0
Run Code Online (Sandbox Code Playgroud)
没有空闲空间!这个页面被我们的 4 行打得满满当当。
归档时间: |
|
查看次数: |
470 次 |
最近记录: |