在事务期间禁用约束
Posted
技术标签:
【中文标题】在事务期间禁用约束【英文标题】:Disable constraints during transaction 【发布时间】:2011-02-20 13:22:29 【问题描述】:我正在整理一个表格,用于向某些信息请求发送后续消息。向一组人发送请求并跟踪响应。如果一个人没有响应,则可能会发送零个或多个跟进。我创建了一个表:
FollowupId int primary key,
RequestId int foreign key (outside this example),
Follows int foreign key (FollowupId),
Message varchar
如果一条消息是第一条后续消息,Follows 将为空。否则,它是其他一些后续的 id。我还在 Follows 上添加了一个独特的约束。也就是说,任何给定的消息后面只能有一条消息。
编辑:我还应该在 Follows 上突出显示外键。它引用此表中的 FollowupId。所以如果 A->B->C,仅仅删除 B 会使 C 中的外键失效。同样,不可能只更新 C 以跟随 A,因为 B 已经跟随 A,并且唯一约束禁止重复。
当然,问题是,如果该消息后面跟着另一个消息,那么现在删除后续条目会很困难。在我看来,应该可以禁用约束检查以删除中间跟进,“向上移动”后续跟进,然后重新启用检查。有没有办法只?
(另外,我知道在此表中包含 RequestId 可能会导致数据不一致。最好包含 Followups [FollowupId, Message]、InitialFollowups [FollowupId, RequestId] 和 FollowFollowups [FollowupId, Follows]表。我认为这不必要地使这个例子复杂化。)
【问题讨论】:
【参考方案1】:我发现(至少在 SQL Server 上)不可能禁用唯一约束。可以禁用外键约束,将要删除的记录的 id 设置为无效且不可能的 id(例如在我的情况下为 -1),更改后续 id,删除有问题的记录,然后恢复约束检查。假设以下数据:
FollowId | RequestId | Follows | Message
--------------------------------------------------------------------
1 | 17 | NULL | "First one"
2 | 17 | 1 | "Second one, delete this one"
3 | 17 | 3 | "Third one, but make it the second"
我使用了以下策略:
BEGIN TRANSACTION;
ALTER TABLE RequestFollowups NOCHECK CONSTRAINT FK_Follows_FollowId;
UPDATE RequestFollowups SET Follows = -1 WHERE FollowupId = 2;
UPDATE RequestFollowUps SET Follows = 1 WHERE FollowupId = 3;
DELETE FROM RequestFollowups WHERE FollowupId = 2;
ALTER TABLE RequestFollowups WITH CHECK CHECK CONSTRAINT FK_Follows_FollowId;
COMMIT TRANSACTION;
(注意倒数第二行的CHECK CHECK
is intentional and not a typo。)
【讨论】:
请注意,使用此方法的不利之处在于,当执行CHECK CHECK CONSTRAINT
步骤时,将对整个表 的约束进行验证,这会对性能产生重大影响。更好的方法是使用可延迟约束,但是 SQL Server 仍然不支持它们。【参考方案2】:
为某些修改禁用/启用约束通常是个坏主意,而且性能可能会很糟糕。每当您执行此操作时,请确保您的约束不仅已启用,而且在您完成后受信任。
在您的情况下,您需要删除一行并修改另一行。如果您已经使用 SQL 2008,则应该使用 MERGE,它允许您在一个命令中同时删除和更新。
【讨论】:
通常是个坏主意,但有时却是个好主意:How to truncate a foreign key constrained table?【参考方案3】:先更新其他值,然后再删除。
所以如果订单是
A -> B -> C
而你正在删除 B,将 C 的 Follows 更新为 A,A 的 FollowedUp 更新为 C,然后删除 B。
【讨论】:
以上是关于在事务期间禁用约束的主要内容,如果未能解决你的问题,请参考以下文章