2010-05-06 115 views
4

我有一個SQL 2005表,裏面有數以百萬計的行,整天都在用戶點擊。該表由20個左右的具有外鍵約束的其他表引用。我需要定期執行的操作是刪除此表中「活動」字段設置爲false的所有記錄,並且在引用父記錄的任何子表中沒有其他記錄。這樣做最有效的方法是什麼?儘量一次刪除每一個,並讓它在違反約束的情況下導致SQL錯誤?此外,它不是一個禁用約束的選項,並且我無法在父表上鎖定任何大量時間。刪除所有沒有外鍵約束的記錄

回答

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 
0

對你的問題有點困惑。但是你可以從你的主表執行一個LeftOuterJoin,到一個應該有一個外鍵的表。然後,您可以使用Where語句來檢查連接表內的空值。

入住這裏外連接:http://en.wikipedia.org/wiki/Join_%28SQL%29#Left_outer_join

你也應該寫觸發條件做這一切爲你當一條記錄被刪除或設置爲false等

+0

觸發的想法是好的,但不能在這種情況下使用,因爲成千上萬的記錄得到一次定期設置爲false,將觸發對錶將導致每個停用批次的每個記錄都有單獨的事務。 – 2010-05-07 00:09:09

+0

@Rodney Burton觸發器在每個語句中調用(即單個UPDATE批處理),而不是每行受影響,但它並不總是一個好主意。 – 2010-05-07 00:22:54

3

讓我們我們有父表的名稱Parent和它在任何類型和類型bit的「Active」字段的「id」字段。我們還有第二個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