【问题标题】:Delete all records that have no foreign key constraints删除所有没有外键约束的记录
【发布时间】:2011-02-16 15:14:50
【问题描述】:

我有一个 SQL 2005 表,其中包含数百万行,用户日夜不停地点击它。该表被 20 个左右具有外键约束的其他表引用。我需要定期做的是从该表中删除所有记录,其中“活动”字段设置为 false 并且在任何引用父记录的子表中都没有其他记录。除了尝试一次删除每个并让它导致违反约束的 SQL 错误之外,最有效的方法是什么?此外,禁用约束也不是一个选项,并且我不能在任何大量时间内导致父表上的锁定。

【问题讨论】:

    标签: sql sql-server foreign-keys constraints rowdeleting


    【解决方案1】:

    对你的问题有点困惑。但是你可以从你的主表做一个 LeftOuterJoin,到一个应该有外键的表。然后,您可以使用 Where 语句检查连接表中的空值。

    在此处检查外部连接:http://en.wikipedia.org/wiki/Join_%28SQL%29#Left_outer_join

    当记录被删除或设置为 false 等时,您还应该编写触发器来为您执行所有这些操作。

    【讨论】:

    • 触发器的想法很好,但不能在这种情况下使用,因为成千上万的记录会定期设置为 false,并且在表上放置触发器会导致单独的每批停用的每条记录的事务。
    • @Rodney Burton 每个语句(即单个 UPDATE 批处理)调用触发器,而不是每个受影响的行,但这仍然不是一个好主意。
    【解决方案2】:

    如果未链接的非活动行不太可能被链接,您可以运行(甚至动态构建,基于外键元数据):

    SELECT k.*
    FROM k WITH(NOLOCK)
    WHERE k.Active = 0
    AND NOT EXISTS (SELECT * FROM f_1 WITH(NOLOCK) WHERE f_1.fk = k.pk)
    AND NOT EXISTS (SELECT * FROM f_2 WITH(NOLOCK) WHERE f_2.fk = k.pk)
    ...
    AND NOT EXISTS (SELECT * FROM f_n WITH(NOLOCK) WHERE f_n.fk = k.pk)
    

    您可以很容易地将其转换为 DELETE。但是一个大的删除可能会持有很多锁,所以你可能想把它放在一个表中,然后批量删除——除非一条记录被链接,否则一个批处理不应该失败。

    为了提高效率,您确实需要在相关表中的 FK 列上建立索引。

    您也可以使用左连接来执行此操作,但是您(有时)必须使用 DISTINCT 或 GROUP BY 进行重复数据删除,并且执行计划通常不会更好,并且不利于代码生成:

    SELECT k.*
    FROM k WITH(NOLOCK)
    LEFT JOIN f_1 WITH(NOLOCK) ON f_1.fk = k.pk
    LEFT JOIN f_2 WITH(NOLOCK) ON f_2.fk = k.pk
    ...
    LEFT JOIN f_n WITH(NOLOCK) ON f_n.fk = k.pk
    WHERE k.Active = 0
        AND f_1.fk IS NULL
        AND f_2.fk IS NULL
        ...
        AND f_n.fk IS NULL
    

    【讨论】:

      【解决方案3】:

      让我们有一个名为Parent 的父表,它在“id”具有任何类型的字段和一个“Active”类型的bit 字段。我们还有第二个Child 表,它有自己的“id”字段和“fk”字段,这是对Parent 表的“id”字段的引用。然后你可以使用以下语句:

      DELETE Parent
      FROM Parent AS p LEFT OUTER JOIN Child AS c ON p.id=c.fk
      WHERE c.id IS NULL AND p.Active=0
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2019-04-26
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多