我有一个SQL 2005表,其中包含数百万行,这些行被用户整天瞄准。该表由20个左右的具有外键约束的表引用。我需要定期做的是删除此表中“Active”字段设置为false的所有记录,并且在引用父记录的任何子表中没有其他记录。如果没有尝试一次删除每个错误并让它导致违反约束的SQL错误,那么最有效的方法是什么?此外,它不是禁用约束的选项,并且我不能在任何大量时间内导致父表上的锁定。
答案 0 :(得分: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
答案 1 :(得分:4)
让我们拥有名为Parent
的父表,它包含任何类型的“id
”字段和Active
类型的“bit
”字段。我们还有第二个Child
表,其中包含自己的“id
”字段和“fk
”字段,该字段是对{{1}的“id
”字段的引用表。然后您可以使用以下语句:
Parent
答案 2 :(得分:0)
对你的问题略感困惑。但是你可以从你的主表中执行一个LeftOuterJoin,到一个应该有一个外键的表。然后,您可以使用Where语句检查连接表中的空值。
点击此处查看外部联接:http://en.wikipedia.org/wiki/Join_%28SQL%29#Left_outer_join
当删除记录或将记录设置为false等时,您还应该编写触发器来为您完成所有这些操作。