4

我有一个将行从一个数据库移动到另一个数据库的过程。由于一些循环外键引用链,我无法从旧数据库中删除行,也无法将它们插入新数据库。

由于整个操作发生在事务1中,我希望 SQL Server 忽略引用完整性失败,直到我调用COMMIT TRANSACTION

例如2

   Table: Turboencabulators         Table: Marselvanes
   =========================        =======================
PK TurboencabulatorID int    /-> PK MarselvaneID       int
^  MarselvanesID      int --/       HasGrammeter       bit
|                                   PantametricFan     varchar(50)
+-------------------------------    TurboencabulatorID int

如果我尝试将turboencabulator插入新表中,它会在没有marselvane的情况下失败。颠倒顺序也有同样的问题。

尝试删除旧行时,我无法删除其中一个,直到另一个被删除。

我尝试过做一个n阶段系统,其中插入所有行,并将外键约束下的任何列设置为null。然后我更新所有插入的行,放置正确的缺失值。然后,为了删除源行,我将受FK影响的所有列清空,然后删除实际行。3

我真正喜欢的是只执行我的 T-SQL 操作,并且在我尝试调用 commit 之前让 SQL Server 不告诉我。

笔记

1分布式
2人为的假设
3我不再做

4

2 回答 2

11

您可以使用 ...

ALTER TABLE whatever_table NOCHECK CONSTRAINT ALL 

在开始之前删除约束检查

完成后用...重新打开它

ALTER TABLE whatever_table CHECK CONSTRAINT ALL 

这就是我无论如何都会做的。

-大学教师

于 2010-02-26T22:06:07.150 回答
2

想象一下你将如何实现它。

如果外键结果将被推迟到事务提交,则提交必须执行在插入/删除/更新时未发生的所有查找/检查/级联操作。想想 FK 约束的真正含义:您的插入执行计划通过额外的操作得到“注释”,以验证和强制执行 FK 约束。如果您推迟约束,则查询计划中的附加逻辑必须从执行时刻解除绑定并推送到某些事务上下文中,以便在提交时执行。所有突然的提交都从简短的“标记事务在日志中提交”操作转变为执行实际事务期间跳过的所有事情的操作。最糟糕的部分是约束可能会失败,并考虑应用程序将如何处理失败? 在执行插入时强制执行约束,应用程序可以捕获错误并采取纠正措施:它准确地知道失败的原因。但是,如果您将其推迟到提交,您会尝试提交并捕获异常,现在您需要以某种方式从咳嗽异常中找出失败的原因。想想在这种情况下应用程序开发人员的生活会有多复杂。

这不起作用的第二个原因是您仍然没有解决问题。您将带有 FK 约束的表 A 放入 B。您开始事务,插入 B,然后插入 A,然后从 A 中删除,然后从 B 中删除,然后提交。所有操作在它们发生的那一刻都满足 FK,数据库在提交时满足 FK。但是,如果您推迟约束检查,它们将在提交时失败!

所以我会说参照完整性可以正常工作,但它是为无循环的级联层次结构而设计的。与许多 CS 数据结构和算法一样,在引入循环时它会中断。最好的解决方案是分析模式,看看循环是否真的不可避免。除此之外,插入 NULL 和更新 post insert 是最好的解决方案。

不幸的是,禁用约束并重新启用是一个很大的禁忌:重新启用必须检查表中的每一行以验证约束,并且将永远持续下去。否则,约束在数据库元数据中被标记为“不受信任”,优化器基本上会忽略它(仍然会强制执行,但您不会从中获得计划优化的好处)。

于 2010-02-26T23:24:43.217 回答