代码之家  ›  专栏  ›  技术社区  ›  Ian Boyd

SQL Server:如何在提交之前忽略引用完整性?

  •  3
  • Ian Boyd  · 技术社区  · 15 年前

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

    因为整个操作发生在事务中 ,我希望SQL Server在调用之前忽略引用完整性失败。 COMMIT TRANSACTION .

    例如 以下内容:

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

    如果我试图插入 涡轮增压器 在新表中,如果没有 马赛尔凡 已经在那里了。颠倒订单也有同样的问题。

    当试图删除旧行时,在删除另一行之前,我不能删除其中一行。

    我试过做一个 n -阶段系统,在其中插入所有行,并将所有受外键约束的列设置为 无效的 . 然后,我更新所有插入的行,放置正确的丢失值。然后,为了删除源行,我将所有受 FK ,然后删除实际行。

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

    笔记

    分布式的
    人为假设
    我再也不做了

    2 回复  |  直到 15 年前
        1
  •  11
  •   Don Dickinson    15 年前

    你可以用…

    ALTER TABLE whatever_table NOCHECK CONSTRAINT ALL 
    

    在开始之前删除约束检查

    完成后,用…

    ALTER TABLE whatever_table CHECK CONSTRAINT ALL 
    

    不管怎样,这就是我要做的。

    -唐

        2
  •  2
  •   Remus Rusanu    15 年前

    想象一下,您将如何实现这一点。

    如果外键结果在事务提交之前是默认的,那么提交必须执行在插入/删除/更新时没有发生的所有查找/检查/级联操作。想想FK约束的真正含义:您的插入执行计划将通过附加操作得到“注释”,以验证和实施FK约束。如果延迟约束,则查询计划中的附加逻辑必须从执行时解除绑定,并推送到某些事务上下文中,以便在提交时执行。所有突然的提交都从短的“mark transaction committed in log”操作转变为执行实际事务期间跳过的所有操作的操作。最糟糕的是,约束可能会失败,并认为 应用程序如何处理失败 ?在执行插入时强制执行约束,应用程序可以捕获错误并采取相应的操作:它知道什么失败了。但是如果您将此延迟到提交,那么您将尝试提交并捕获一个异常,现在您需要以某种方式从正确的异常中找出失败的原因。想想在这种情况下,应用程序开发人员的生活会有多复杂。

    这不起作用的第二个原因是你仍然没有解决问题。表A的fk约束为b。开始事务处理,插入到b,然后插入到a,然后从a中删除,然后从b中删除,然后提交。所有操作在发生时都满足FK,数据库在提交时满足FK。但是,如果您推迟约束检查,它们将 失败 在承诺的时间!!

    所以我想说,引用完整性工作得很好,但它是为一个没有循环的级联层次而设计的。和许多CS数据结构和算法一样,当循环被生成时,它会中断。最好的解决方案是分析模式,看看周期是否真的不可避免。除此之外,插入空值和更新后插入是最好的解决方案。

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