varbinary(16)上的ANSI_PADDING无法正常工作

时间:2018-10-18 03:29:35

标签: sql sql-server tsql sql-server-2017

当我将具有默认约束0x00000000000000000000000000000000的新的定长varbinary列添加到现有的非空表中时,表中的现有记录将收到修剪后的默认约束{{1 }}。

随后插入的新记录确实正确应用了默认约束。

这仅发生在SQL 2017中,SQL的早期版本正确地将默认约束应用于所有现有记录。

包括'SET ANSI_PADDING ON'不会影响结果。

0x00 ...的行为也相同,它会修剪尾随零。

我也尝试使用默认值0x11111111110000000,但结果相同。


运行Microsoft SQL Server 2017(RTM-CU11)(KB4462262)-14.0.3038.14(X64)


要复制:

DEFAULT Cast(0x00000000000000000000000000000000 as varbinary(16))

结果:

create table #test (id int);
insert into #test (id) values (1), (2), (3);
alter table #test add testvarbinary VARBINARY(16) NOT NULL CONSTRAINT 
DF_MyTable_NewColumn DEFAULT 0x00000000000000000000000000000000;
insert into #test (id) values (4); 
select * from #test;

1 个答案:

答案 0 :(得分:2)

有一个功能introduced in SQL Server 2012,该功能允许将NOT Null列添加到现有表中(具有默认约束) 这是为了允许将非空添加到非常大的表中。

这仅限于企业版和功能上等效的SKU,这就是为什么您只能在测试中的某些实例上看到它的原因。

它的工作方式是将现有行保留NULL直到下一次触摸并从元数据中检索值。

元数据本身很好,可以使用

检查
SELECT pc.default_value
FROM   tempdb.sys.system_internals_partitions p
       JOIN tempdb.sys.system_internals_partition_columns pc
         ON p.partition_id = pc.partition_id
WHERE  p.object_id = OBJECT_ID('tempdb..#test')
       AND default_value IS NOT NULL; 

但是当读取值时,会发生对0x00的更改。

有趣的是-如果您将默认设置更改为0x00000000000000000000000000000001 然后所有行都将更新为正确的值:

id  testvarbinary
1   0x00000000000000000000000000000001
2   0x00000000000000000000000000000001
3   0x00000000000000000000000000000001
4   0x00000000000000000000000000000001

一种可能的解决方法是使默认约束没有确定性(并且不可能将其作为运行时常量进行缓存),以防止在线列的添加。尽管您随后失去了该功能的性能优势。

以下默认约束表达式避免了该问题

DEFAULT 0x00000000000000000000000000000000 + CAST(LEFT(NEWID(),0) AS varbinary(1))

您应将其报告为the uservoice site上的错误。