6

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

4

3 回答 3

7

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

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
于 2010-05-06T23:53:47.010 回答
4

让我们有父表的名称Parent,它有id任何类型的“ Active”字段和类型的“”字段bit。我们还有第二个Child表,其中包含他自己的“ id”字段和“ ”字段,该字段是对表的“”字段fk的引用。然后您可以使用以下语句:idParent

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
于 2010-05-07T00:18:40.913 回答
0

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

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

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

于 2010-05-06T23:53:07.450 回答