我创建了一个包含 650 个 Numeric(19,4) 列的表。当我打开页面压缩时,通过运行
ALTER TABLE fct.MyTable REBUILD WITH (DATA_COMPRESSION = PAGE);
我明白了
消息 1975,级别 16,状态 1
索引“PK_Mytable”行长度超过了“8060”字节的最大允许长度。
但是 650 乘以 9 字节只有 5850 字节,与规定的 8060 字节限制相去甚远。
服务器正在运行带有 SQL Server 2016 SP1 CU2 的 Windows 2012 r2
使用页面压缩时的行开销是多少?
这是一些代码来说明我的意思:
/* 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
行压缩也会失败,但行数不同。
如果您尝试在没有集群 PK 约束的情况下创建表,您会得到一个稍微不同的错误:
在此错误消息中,您可以看到页面压缩有 1530 字节的内部开销。
现在,您可以进行数学运算:
bigint
MyTableID 8 个字节int
LastColumn 4 个字节numeric(19,4)
(总共 5337 个字节)所以,8 + 4 + (593*9) + 1530 = 6879。 等一下.... 仍然低于 8060。这是怎么回事?!
Page Compression 算法实际上是把几个压缩算法堆叠在一起。第一步是应用 ROW 压缩。行压缩的开销不包括在该错误消息中列出的 1530 字节开销中。
您可以在我的博客和BOL中阅读有关行压缩如何工作的更多信息。您将在 BOL 文章中注意到,它将
numeric
存储描述为“此存储与 vardecimal 存储格式完全相同”,但没有解释vardecimal
. 这篇文章涵盖vardecimal
了更多内容——本质上,它为每列增加了 2 个字节的开销来存储实际长度(类似于varchar
所做的)。行压缩对于 593 列中的每一列都需要额外的 2 个字节
numeric
,再加上bigint
和,每列int
将需要 1 个字节的开销。行压缩存储要求为:
bigint
MyTableID的 8 字节 + 1 字节开销int
LastColumn的 4 字节 + 1 字节开销numeric(19,4)
593列中的每一列的 9 字节 + 2 字节开销8 + 4 + (593*9) = 5349 字节数据
1 + 1 + (593*2) = 1188 字节行压缩开销
行压缩模式总共 6537 字节
现在我们有了行压缩模式的行大小,我们可以重新审视我们的数学。页面压缩的行大小将是数据大小 + 行压缩开销 + 页面压缩开销:
bigint
MyTableID 8 个字节int
LastColumn 4 个字节numeric(19,4)
593列中的每一列 9 个字节总共 8067 字节