使用页面压缩时的行开销是多少?

Hen*_*sen 10 data-pages compression sql-server-2016

我创建了一个包含 650 个 Numeric(19,4) 列的表。当我打开页面压缩时,通过运行

ALTER TABLE fct.MyTable REBUILD  WITH (DATA_COMPRESSION = PAGE);
Run Code Online (Sandbox Code Playgroud)

我得到

消息 1975,级别 16,状态 1
索引“PK_Mytable”行长度超过了“8060”字节的最大允许长度。

但是 650 乘以 9 字节仅为 5850 字节,这与规定的 8060 字节的限制相去甚远。

服务器运行的是 Windows 2012 r2 和 SQL Server 2016 SP1 CU2

使用页面压缩时的行开销是多少?

这是一些代码来显示我的意思:

/* test script to demo MSG 1975 */
DECLARE @sql NVARCHAR(max)='', @i INT =0
drop table if exists dbo.mytable;

SET @sql = 'Create table dbo.Mytable (MyTableID bigint not null 
  identity(1,1) primary key clustered, '

WHILE @i < 593 BEGIN
    SET @sql += ' Column' + LTRIM(@i) + ' numeric(19,4) null, '
    SET @i +=1
END

SET @sql += ' LastColumn int) '
--SET @sql += ' with (DATA_COMPRESSION = ROW) '
SET @sql += ' with (DATA_COMPRESSION = PAGE) '

SELECT @sql
EXEC sys.sp_executesql @sql

SELECT top 10000 * FROM dbo.MyTable MT
Run Code Online (Sandbox Code Playgroud)

行压缩也失败,但行数不同。

AMt*_*two 13

如果您尝试在没有集群 PK 约束的情况下创建表,您会得到一个稍微不同的错误:

消息 1701,级别 16,状态 1,第 1 行创建或更改表“Mytable”失败,因为最小行大小为 8067,包括 1530 字节的内部开销。这超出了 8060 字节的最大允许表行大小。

在此错误消息中,您可以看到页面压缩有 1530 字节的内部开销。

现在,您可以计算一下:

  • bigintMyTableID 8 个字节
  • intLastColumn 4 个字节
  • 593numeric(19,4)列中的每列9 个字节(总共 5337 个字节)
  • 1530 字节的压缩开销

所以,8 + 4 + (593*9) + 1530 = 6879。 等一下…… 这仍然低于 8060。这是怎么回事?!


页面压缩算法实际上将几种压缩算法堆叠在一起。第一步是应用 ROW 压缩。行压缩的开销不包括在该错误消息中列出的 1530 字节开销中。

您可以在我的博客BOL 中阅读有关行压缩如何工作的更多信息。您会在 BOL 文章中注意到,它将numeric存储描述为“此存储与 vardecimal 存储格式完全相同”,但没有解释vardecimal. 这篇文章涵盖vardecimal了更多内容——本质上,它为每列增加了 2 个字节的开销来存储实际长度(类似于varchar所做的)。

对于 593numeric列中的每一列,行压缩将需要额外的 2 个字节,加上bigintint将需要的开销每1个字节。

行压缩存储的要求是:

  • bigintMyTableID 的8 个字节 + 1 个字节的开销
  • intLastColumn 的4 个字节 + 1 个字节的开销
  • 9 字节 + 593numeric(19,4)列中每列的2 字节开销
  • 1188 字节的 ROW 压缩开销

8 + 4 + (593*9) = 5349 字节数据

1 + 1 + (593*2) = 1188 字节行压缩开销

行压缩模式总共 6537 字节


现在我们有了行压缩模式的行大小,我们可以重新审视我们的数学。页压缩的行大小将是数据大小 + 行压缩开销 + 页压缩开销:

  • bigintMyTableID 8 个字节
  • intLastColumn 4 个字节
  • 593numeric(19,4)列中的每列9 个字节
  • 1188 字节的 ROW 压缩开销
  • 1530 字节的 PAGE 压缩开销
  5349 字节数据 
+ 1188 字节行压缩开销 
+ 1530 字节页面压缩开销 

总共 8067 字节

  • @HenrikStaunPoulsen 要记住的另一件重要事情是 SQL Server 需要假设您的数据可能无法压缩。因此,即使*您的数据* 将压缩到小于 8060 字节,SQL Server 也必须根据不可压缩数据的理论最大行大小进行行大小计算。 (2认同)