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 字节的内部开销。
现在,您可以计算一下:
bigint
MyTableID 8 个字节int
LastColumn 4 个字节numeric(19,4)
列中的每列9 个字节(总共 5337 个字节)所以,8 + 4 + (593*9) + 1530 = 6879。 等一下…… 这仍然低于 8060。这是怎么回事?!
页面压缩算法实际上将几种压缩算法堆叠在一起。第一步是应用 ROW 压缩。行压缩的开销不包括在该错误消息中列出的 1530 字节开销中。
您可以在我的博客和BOL 中阅读有关行压缩如何工作的更多信息。您会在 BOL 文章中注意到,它将numeric
存储描述为“此存储与 vardecimal 存储格式完全相同”,但没有解释vardecimal
. 这篇文章涵盖vardecimal
了更多内容——本质上,它为每列增加了 2 个字节的开销来存储实际长度(类似于varchar
所做的)。
对于 593numeric
列中的每一列,行压缩将需要额外的 2 个字节,加上bigint
和int
将需要的开销每1个字节。
该行压缩存储的要求是:
bigint
MyTableID 的8 个字节 + 1 个字节的开销int
LastColumn 的4 个字节 + 1 个字节的开销numeric(19,4)
列中每列的2 字节开销8 + 4 + (593*9) = 5349 字节数据
1 + 1 + (593*2) = 1188 字节行压缩开销
行压缩模式总共 6537 字节
现在我们有了行压缩模式的行大小,我们可以重新审视我们的数学。页压缩的行大小将是数据大小 + 行压缩开销 + 页压缩开销:
bigint
MyTableID 8 个字节int
LastColumn 4 个字节numeric(19,4)
列中的每列9 个字节5349 字节数据 + 1188 字节行压缩开销 + 1530 字节页面压缩开销