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