sql server 2012 - 检查约束

时间:2016-05-09 10:17:49

标签: sql-server sql-server-2012

我正在使用SQL Server 2012 Management Studio。以下是我要写的内容。我真的很感激一些帮助。

ALTER TABLE [tablename] WITH CHECK ADD CONSTRAINT [constraintname] CHECK  
(([column]='A' OR [column]='B' OR [column]='C' OR [column]='D'))

但是当我们通过SQL Server 2012 Management Studio生成脚本时,我收到以下声明..

ALTER TABLE [tablename] WITH NOCHECK ADD CONSTRAINT [constraintname] CHECK  
(([column]='A' OR [column]='B' OR [column]='C' OR [column]='D'))
GO
ALTER TABLE [tablename] CHECK CONSTRAINT [constraintname]

为什么生成的脚本首先使用nocheck构建,然后对表进行检查?如果我在没有nocheck的情况下创建检查约束会发生什么?

2 个答案:

答案 0 :(得分:2)

生成的脚本使用NOCHECK,因此即使表中的值不符合,也始终会创建约束。这对于自动生成的脚本更好,因为它可以确保正确创建或修改数据库模式。

我首先想到,生成的脚本中的第二个语句是确保查询优化器将考虑约束。 (参见下面的参考文献。)然而,在进一步调查中,似乎第二个陈述没有任何影响 - 请参阅我的第二个答案。

当您手动执行此操作时,使用WITH CHECK,您可以立即看到该语句失败并采取纠正措施。然后再次运行该语句。

如果使用WITH NOCHECK选项,则可能不会注意到数据无效。就个人而言,我总是在做ALTER TABLE时使用WITH CHECK来添加约束。此外,联机丛书表示不建议使用WITH NOCHECK,除非在极少数情况下 - 请参阅下面的参考资料。

为了证明这种差异,我们首先创建一个表并插入一些值。

CREATE TABLE dbo.T
(
    id int NOT NULL IDENTITY(1,1),
    [column] nchar(1) NOT NULL
);

INSERT INTO dbo.T ([column])
    VALUES (N'A'), (N'B'), (N'C'), (N'E');

尝试更改表并添加约束,指定WITH CHECK。这会失败,因为表中的某些数据不符合约束条件。

ALTER TABLE dbo.T
    WITH CHECK
    ADD CONSTRAINT CK_Column CHECK ([column] IN (N'A', N'B', N'C', N'D'));

enter image description here

通过使用sys.check_constraints系统目录视图,让我们看看是否已创建约束。这表明尚未创建约束。

SELECT *
    FROM sys.check_constraints
    WHERE [parent_object_id] = OBJECT_ID(N'dbo.T');

enter image description here

再次尝试,这次指定WITH NOCHECK。这次成功完成。但是,没有警告表中的数据无效,这可能是不合需要的。

ALTER TABLE dbo.T
    WITH NOCHECK
    ADD CONSTRAINT CK_Column CHECK ([column] IN (N'A', N'B', N'C', N'D'));

enter image description here

我们可以验证是否已创建检查约束。

enter image description here

请参阅联机丛书> ALTER TABLE(Transact-SQL):https://msdn.microsoft.com/en-GB/library/ms190273.aspx>与检查|没有检查

  

如果您不想针对现有数据验证新的CHECK或FOREIGN KEY约束,请使用WITH NOCHECK。除极少数情况外,我们不建议这样做。将在所有后续数据更新中评估新约束。添加约束时由WITH NOCHECK抑制的任何约束违规可能会导致将来更新失败,如果他们使用不符合约束的数据更新行。

此处显示第二个自动生成的语句的原因:

  

查询优化器不考虑使用NOCHECK定义的约束。在使用ALTER TABLE表WITH CHECK CHECK CONSTRAINT ALL重新启用它们之前,将忽略此类约束。

答案 1 :(得分:1)

在我之前的回答后深入挖掘......

如果在使用WITH NOCHECK选项创建CHECK约束后运行以下语句,我们可以看到约束已启用(is_disabled = 0),但它不受信任。

SELECT name, is_disabled, is_not_trusted
    FROM sys.check_constraints
    WHERE [parent_object_id] = OBJECT_ID(N'dbo.T');

enter image description here

运行SSMS生成的第二个语句没有任何区别。检查约束仍然不受信任,并且已经启用。

ALTER TABLE dbo.T
    CHECK CONSTRAINT CK_Column;

我们必须修复数据。 (或改变约束。)

UPDATE dbo.T
    SET [column] = N'D'
    WHERE [column] = N'E';

然后运行此语句。请注意,这次我们指定WITH CHECK,以便验证数据。

ALTER TABLE dbo.T
    WITH CHECK
    CHECK CONSTRAINT CK_Column;

最后我们可以看到约束变得可信(is_not_trusted = 0),这意味着它可以被查询优化器使用。

SELECT name, is_disabled, is_not_trusted
    FROM sys.check_constraints
    WHERE [parent_object_id] = OBJECT_ID(N'dbo.T');

enter image description here

因此,总而言之,就我所见,SSMS生成的第二个语句没有用处,因为约束已经启用。

请参阅联机丛书> sys.check_constraints(Transact-SQL):https://msdn.microsoft.com/en-GB/library/ms187388.aspx

另见联机丛书> ALTER TABLE(Transact-SQL):https://msdn.microsoft.com/en-GB/library/ms190273.aspx> {检查| NOCHECK} CONSTRAINT

  

指定启用或禁用constraint_name。此选项只能与FOREIGN KEY和CHECK约束一起使用。指定NOCHECK时,将禁用约束,并且不会根据约束条件验证将来对列的插入或更新。无法禁用DEFAULT,PRIMARY KEY和UNIQUE约束。

SQLServerCentral.com>检查和外键约束提高了查询性能:http://www.sqlservercentral.com/articles/Performance+Tuning/71264/