2个SQL服务器中的不同行为

时间:2015-01-12 00:06:10

标签: sql-server

我有一个运行一些集成测试的项目。该项目每次都会创建一个新数据库,并针对这个新数据库运行测试。最近我把这个项目搬到了一个新的服务器上,当从数据库中删除数据时我遇到了一些问题。

我执行以下查询:

DELETE FROM TABLE1;
DELETE FROM TABLE2;
DELETE FROM TABLE3;

在服务器A上,一切都按预期工作,但是使用服务器B我收到以下错误:

  

DELETE语句与REFERENCE约束冲突   " FK _....&#34 ;.冲突发生在数据库中   " TestDB",table" Table1",column   ' ...'

两台服务器都具有相同版本的SQL Server

Microsoft SQL Server 2012 (SP1) - 11.0.3401.0 (X64) 
    Jan  9 2014 13:22:15 
    Copyright (c) Microsoft Corporation
    Standard Edition (64-bit) on Windows NT 6.2 <X64> (Build 9200: ) (Hypervisor)

架构和数据都相同,并且使用相同的流程创建数据库。

任何想法?

3 个答案:

答案 0 :(得分:3)

实际上,两个地方都可以使用相同的模式,甚至可以使用相同的数据,并且会遇到不同的行为。怎么样?因为可以禁用约束(CHECK和FOREIGN KEY)。烨。

要查看有问题的外键是启用还是禁用,只需运行以下命令,确保在WHERE子句中放入有问题的FK名称:

SELECT *
FROM sys.foreign_keys
WHERE [name] = N'{name_of_FK_in_question}';

查看名为is_disabled的列。我怀疑它在服务器A上设置为1(其中一切都“有效”)并且在服务器B上设置为0(事情“不起作用”)。我把“工作”和“不工作”放在引号中,因为如果确实如此,那么现实就与你所经历的相反。这意味着,启用FK并获得错误的系统实际上正在工作,因为这就是FK应该做的事情。没有出错的系统可能允许孤立(即坏)数据。

要启用FK,请运行以下命令:

ALTER TABLE {table_name}
   WITH CHECK -- verifies the data currently in the table
   CHECK CONSTRAINT [{name_of_FK_in_question}];

当然,如果存在不良数据,您需要:

  • 首先删除错误数据,或

  • WITH NOCHECK上指定ALTER,以便接受错误数据:

    ALTER TABLE {table_name}
       WITH NOCHECK -- accept the bad data aleady there
       CHECK CONSTRAINT [{name_of_FK_in_question}];
    

    然而,这并不能100%解决问题。如果再次运行SELECT查询(如上所述),您应该会看到is_disabled字段现在设置为0。但是,如果您查看is_not_trusted字段,则会将其设置为1。如果某个约束已启用但尚未受信任,它将按预期强制执行其规则,但查询优化器(QO)将忽略它,这通常不是一件好事,因为约束实际上不仅用于强制执行数据完整性规则,而且也作为QO的线索逻辑上减少某些查询中的某些步骤(即它们有时有助于提高性能)。为了使约束成为“受信任”,您必须删除错误数据并通过以下方式验证表中的所有约束:

    ALTER TABLE {table_name}
       WITH CHECK -- verifies the data currently in the table
       CHECK CONSTRAINT [{name_of_FK_in_question}];
    

    但是,如果由于某种原因你需要“坏”数据,那么你将只有一个外键来强制数据完整性,但没有提高性能的潜力(仍然是比没有定义FK更好:)。

有关详细信息,请参阅ALTER TABLE的MSDN页面。


为了完整起见,我还要提到在服务器A(没有错误的地方)上可能会使用选项ON DELETE CASCADE来定义FK,该选项会在之前自动删除和相关数据从正在删除的表中删除行,而服务器B(存在错误)没有指定ON DELETE操作(或指定为NO ACTION)。但是,这是在进行模式比较时应该显示的内容(除非指定忽略ON DELETEON UPDATE操作),而是约束是启用还是禁用在架构比较中更有可能被忽略。

答案 1 :(得分:2)

有一个外键(在错误消息中命名)阻止您从Table1删除项目,因为它会违反外键(即另一个表中会有一行引用你要删除的那一行)

两个数据库之间的区别是:

  • 第一个数据库没有外键
  • 第一个数据库没有受外键约束的表中的任何行

要查找外键所在的表,请参阅问题How can I list all foreign keys referencing a given table in SQL Server?

EXEC sp_fkeys 'TableName'

答案 2 :(得分:0)

像Justin说的那样,无论是密钥还是数据都不一样,如果它适用于您的情况,那么将密钥设置为级联删除将解决此问题,但您必须首先识别密钥。