简体   繁体   English

删除所有没有外键约束的记录

[英]Delete all records that have no foreign key constraints

I have a SQL 2005 table with millions of rows in it that is being hit by users all day and night. 我有一个SQL 2005表,其中包含数百万行,这些行被用户整天瞄准。 This table is referenced by 20 or so other tables that have foreign key constraints. 该表由20个左右的具有外键约束的表引用。 What I am needing to do on a regular basis is delete all records from this table where the "Active" field is set to false AND there are no other records in any of the child tables that reference the parent record. 我需要定期做的是删除此表中“Active”字段设置为false的所有记录,并且在引用父记录的任何子表中没有其他记录。 What is the most efficient way of doing this short of trying to delete each one at a time and letting it cause SQL errors on the ones that violate constraints? 如果没有尝试一次删除每个错误并让它导致违反约束的SQL错误,那么最有效的方法是什么? Also it is not an option to disable the constraints and I cannot cause locks on the parent table for any significant amount of time. 此外,它不是禁用约束的选项,并且我不能在任何大量时间内导致父表上的锁定。

If it's not likely that inactive rows which are not linked will become linked, you can run (or even dynamically build, based on the foreign key metadata): 如果未链接的非活动行不可能链接,则可以运行(甚至基于外键元数据动态构建):

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)

And you can turn it into a DELETE pretty easily. 你可以很容易地把它变成DELETE。 But a large delete could hold a lot of locks, so you might want to put this in a table and then delete in batches - a batch shouldn't fail unless a record got linked. 但是大型删除可能会占用很多锁,因此您可能希望将其放入表中然后批量删除 - 除非记录已链接,否则批处理不应失败。

For this to be efficient, you really need to have indexes on the FK columns in the related tables. 为了提高效率,您确实需要在相关表中的FK列上建立索引。

You can also do this with left joins, but then you (sometimes) have to de-dupe with a DISTINCT or GROUP BY and the execution plan isn't really usually any better and it's not as conducive to code-generation: 您也可以使用左连接执行此操作,但是您(有时)必须使用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

Let us we have parent table with the name Parent and it has at " id " field of any type and an " Active " field of the type bit . 让我们拥有名为Parent父表,它具有任何类型的“ id ”字段和类型为bit的“ Active ”字段。 We have also a second Child table with his own " id " field and " fk " field which is the reference to the " id " field of the Parent table. 我们还有第二个Child表,它有自己的“ id ”字段和“ fk ”字段,它是对Parent表的“ id ”字段的引用。 Then you can use following statement: 然后你可以使用以下语句:

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

Slightly confused about your question. 对你的问题略感困惑。 But you can do a LeftOuterJoin from your main table, To a table that it should supposedly have a foreign key. 但是你可以从你的主表中执行一个LeftOuterJoin,到一个应该有一个外键的表。 You can then use a Where statement to check for null values inside the connecting table. 然后,您可以使用Where语句检查连接表中的空值。

Check here for outer joins : http://en.wikipedia.org/wiki/Join_%28SQL%29#Left_outer_join 点击此处查看外部联接: http//en.wikipedia.org/wiki/Join_%28SQL%29#Left_outer_join

You should also write up triggers to do all this for you when a record is deleted or set to false etc. 当记录被删除或设置为false时,您还应该编写触发器来为您完成所有这些操作。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM