ANSI_PADDING varbinary(16) 不工作

ANSI_PADDING on varbinary(16) not working

当我将默认约束为 0x00000000000000000000000000000000 的新固定长度 varbinary 列添加到现有的非空 table 时,table 中的现有记录正在接收默认约束的修剪版本,0x00.

新记录的后续插入会正确应用默认约束。

这只发生在 SQL 2017 年,以前的版本 SQL 正确地将默认约束应用于所有现有记录。

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

0x11111111110000000... 也以相同的方式运行,它修剪尾随零。

我也尝试过使用默认值 DEFAULT Cast(0x00000000000000000000000000000000 as varbinary(16)),但结果相同。


运行 微软 SQL 服务器 2017 (RTM-CU11) (KB4462262) - 14.0.3038.14 (X64)


重现:

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;

结果:

+----+------------------------------------+
| id |           testvarbinary            |
+----+------------------------------------+
|  1 | 0x00                               |
|  2 | 0x00                               |
|  3 | 0x00                               |
|  4 | 0x00000000000000000000000000000000 |
+----+------------------------------------+

有一项功能 introduced in SQL Server 2012 允许将非空列添加到现有的 table(具有默认约束) 这是为了允许将 not-null 添加到非常大的 tables.

这仅限于企业版和功能等效的 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 上的错误。