改变 table 添加唯一约束而不检查 SSDT

Alter table adding unique constraint with no check SSDT

我有一个 SSDT 项目,我们通过 dacpac/sqlpackage 发布数据库。 现在我有一个包含重复记录的现有 table。 我正在添加一个 UNIQUE 约束,这样记录就不会重复。 这就是我的 table 脚本的样子。

CREATE TABLE [AM].[WorkflowStep]
(
    [Id] INT NOT NULL PRIMARY KEY IDENTITY, 
    [StepName] NVARCHAR(200) NOT NULL, 
    [IsAutomated] BIT NOT NULL DEFAULT 0, 
    [TenantId] UNIQUEIDENTIFIER NOT NULL,
    *CONSTRAINT [UNIQUE_STEP] UNIQUE (StepName, IsAutomated, TenantId)*
)

新增约束条件。我期待 sqlpackage.exe 生成发布脚本,其中添加了 NOCHECK 选项的约束,然后最终使用 CHECK 选项进行了更改。但这并没有发生。该脚本只有一个 alter table 选项。

ALTER TABLE [WorkflowStep]
    ADD CONSTRAINT [UNIQUE_STEP] UNIQUE NONCLUSTERED ([StepName] ASC, [IsAutomated] ASC, [TenantId] ASC);

有人可以解释为什么会这样吗?这是否特定于 UNIQUE 约束。我在其他 table 中有其他约束,sqlpackage 最初使用 NOCHECK 选项添加约束,但它们是外键引用。`

您可以自己轻松测试:

CREATE TABLE #t(ID int); 
INSERT #t(ID) VALUES (1), (1); 
ALTER TABLE #t WITH NOCHECK ADD CONSTRAINT UQ_#t_ID UNIQUE(ID);

The CREATE UNIQUE INDEX statement terminated because a duplicate key was found for the object name 'dbo.#t...' and the index name 'UQ_#t_ID'. The duplicate key value is (1).

这证明NOCHECK被忽略了。 docs 还指定了仅对 FOREIGN KEYCHECK 约束的影响,尽管它们没有说明其他约束的行为是什么。

它以这种方式工作有一个很好的技术原因:UNIQUE 约束必须由索引支持,并且 UNIQUE 索引的物理结构不同于非 UNIQUE索引。具体来说,非 UNIQUE 索引有一个唯一标识符,一个不可见的、可为空的整数列,添加到索引行以使它们无论如何都是唯一的,并允许引擎识别各个行。要允许创建唯一约束 WITH NOCHECK 然后稍后应用 WITH CHECK 实际上需要重建索引,至少更改元数据——这并不比从一开始就正确创建索引更好UNIQUE 或非 UNIQUE,具体取决于您的需要。相比之下,FOREIGN KEY/CHECK 约束总是可以稍后验证,而无需重写数据。