SQL Server 2014 压缩和最大行大小

Ale*_*lex 8 sql-server database-internals compression sql-server-2014

我需要创建包含大量小数 (26,8) 列的宽非规范化表(少于 1024 列限制,大多数列将为空或零)。我知道每行限制为 8060 字节,因此我尝试使用页面压缩创建表。下面的代码创建表,插入一行并查询行大小。行大小远低于限制,但如果我尝试向表中再添加一个小数 (26,8) 列,操作将失败并显示错误“创建或更改表 't1' 失败,因为最小行大小为 8074,包括 1256字节的内部开销。”。有没有办法创建具有这么多列的单个表?

drop table t1
GO
create table t1(c1 decimal(26, 8) null)
with (data_compression = page)
GO

declare @i int = 2;
declare @sql varchar(100);
while @i <= 486
begin
    set @sql = 'alter table t1 add c' + convert(varchar, @i) + ' decimal(26, 8) null';
    execute (@sql);
    set @i += 1;
end;
GO


insert into t1(c1) select 0
GO
declare @i int = 2;
declare @sql varchar(100);
while @i <= 486
begin
    set @sql = 'update t1 set c' + convert(varchar, @i) + ' = 0';
    execute (@sql);
    set @i += 1;
end;
GO

select max_record_size_in_bytes from sys.dm_db_index_physical_stats (db_id(), object_id('t1'), NULL, NULL, 'DETAILED')
GO
Run Code Online (Sandbox Code Playgroud)

Joe*_*ish 4

您遇到的限制与页面上存储的数据无关。计算是根据列的数据类型完成的。这就是为什么您会在表中没有任何数据的情况下遇到错误。压缩使这个限制变得更糟。您可以在此处阅读有关开销背后的技术细节。

您可以通过使用SPARSE列来解决此问题。这意味着插入可能会失败,具体取决于您插入的内容,但您可以绕过 8060 字节限制。以下代码显示您可以很好地创建 1023 列:

drop table t1
GO
create table t1(c1 decimal(26, 8) null)
GO

declare @i int = 2;
declare @sql varchar(100);
while @i <= 1023
begin
    set @sql = 'alter table t1 add c' + convert(varchar, @i) + ' decimal(26, 8) SPARSE null';
    execute (@sql);
    set @i += 1;
end;
GO
Run Code Online (Sandbox Code Playgroud)

但是,它周围的所有限制(阅读链接的文章)可能会使它不适合您的用例。具体来说,只有NULL值(不是0)被优化以占用很少的空间。0如果您尝试在一行中插入太多s,您将收到错误。这是我尝试插入 1023 个0值时看到的内容:

消息 511,级别 16,状态 1,第 1 行 无法创建大小为 17402 的行,该行大于允许的最大行大小 8060。

我想如果你真的绝望了,你可以创建专栏VARCHAR(27)。可变长度列可以移出页面,以便可以超出表定义中的 8060 字节限制,但插入某些值组合将会失败。SQL Server 在创建表时会警告您:

警告:表“t1”已创建,但其最大行大小超出允许的最大值 8060 字节。如果结果行超出大小限制,则对此表的 INSERT 或 UPDATE 将失败。

如果您采用这种VARCHAR(27)方法,页面或行压缩可能会有所帮助。0这将最大限度地减少和所使用的空间NULL。这样VARCHAR(27)我就可以插入 1023 个0值了。