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 上的错误。
当我将默认约束为 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 上的错误。