2009-10-28 66 views
15

在2005年MSSQL我只是擊中了臭名昭著的錯誤消息:外鍵級聯多路徑和週期有什麼問題?

上表YYY引進國外KEY約束XXX可能會導致循環或多個級聯路徑。指定ON DELETE NO ACTION或ON UPDATE NO ACTION,或修改其他FOREIGN KEY約束。現在

,StackOverflow上具有有關此錯誤消息的幾個話題,所以我已經得到了解決(在我來說,我將不得不使用觸發器),但我很好奇,爲什麼有這樣的問題。

據我所知,基本上有兩個他們想要避免的情況 - 一個循環和多個路徑。一個循環是兩個表彼此級聯外鍵的地方。好的,一個循環也可以跨越幾個表格,但這是基本情況,並且將更容易分析。

當TableA具有TableB和TableC的外鍵並且TableB也具有TableC的外鍵時,將有多條路徑。再次 - 這是最基本的情況。

我看不到在任何一個表中記錄被刪除或更新時會出現的任何問題。當然,您可能需要多次查詢同一個表以查看哪些記錄需要更新/刪除,但這確實是一個問題嗎?這是一個性能問題?

在其他SO主題中,人們甚至使用級聯標籤作爲「risky」並聲明「resolving cascade paths is a complex problem」。爲什麼?風險在哪裏?哪裏有問題?

回答

4

您有一張包含來自同一父級的兩個級聯路徑的子表:一個「刪除」,一個「null」。

什麼優先?事後你有什麼期望? etc

注意:觸發器是代碼,可以爲級聯添加一些智能或條件。

0

我同意,級聯是「冒險」,應該避免。 (我個人更喜歡手動級聯更改,而不是讓sql server自動處理它們)。這也是因爲,即使SQL服務器中刪除數百萬行,輸出仍然會顯示爲

(影響1行(S))

+1

用觸發器代替它會更好嗎?當然 - 有這樣一種方法,「根本不使用外鍵」和做代碼的所有事情。我不認爲我需要告訴你爲什麼我認爲這是一個壞主意...... – 2009-10-30 10:28:05

1

我們禁止使用級聯刪除的原因有業績和鎖定做。是的,當你刪除一條記錄時它並不是很糟糕,但遲早你需要刪除一大組記錄,並且你的數據庫將會陷入停頓。

如果您正在刪除足夠的記錄,SQL Server可能會升級到表鎖,並且在完成之前,沒有人可以對錶執行任何操作。

我們最近將我們的一個客戶移到了他自己的服務器上。作爲交易的一部分,我們還必須從原始服務器上刪除客戶的所有記錄。刪除他所有的信息(以免引起其他用戶的問題)需要幾個月的時間。如果我們已經設置了級聯刪除,那麼數據庫將長時間無法訪問其他客戶端,因爲在一個事務中刪除了數百萬條記錄,並且在事務完成之前,數百個表已被鎖定。

我還可以看到使用級聯刪除時可能發生死鎖的場景,因爲我們無法控制級聯路徑會採取的順序,並且我們的數據庫在大多數表中出現clientid時會有點非正常化。因此,如果它將一個外鍵也鎖定到第三個表以及處於不同路徑的客戶表中,它可能無法檢查該表以便從第三個表中刪除,因爲這是全部一個事務,鎖定在完成之前不會被釋放。因此,如果它看到在事務中創建死鎖的可能性,它可能不會讓我們設置級聯刪除。

避免級聯刪除的另一個原因是,有時候子記錄的存在是不足以刪除父記錄的原因。例如,如果您有客戶表並且該客戶過去已有訂單,則您不希望刪除他並丟失實際訂單上的信息。

+4

如果您處理數百萬行,那麼幾乎總是必須使用棘手的解決方法,如批處理,禁用外鍵,運行作業在空閒時間等,但這不是一個日常的情況。人們事先準備好這種事情。他們在測試環境中測試它。他們製作長而扭曲的腳本來調整數據庫,以便獲得可接受的性能。一旦完成,它就會被遺忘。但是「ON DELETE CASCADE」意味着在日常生活中使用,當你沒有刪除數百萬行,但一次最多隻有幾百個。 – 2009-10-30 10:25:16

+0

無論如何可能發生級聯上的死鎖(或甚至簡單地刪除同一表中的多行) - 防止多個級聯路徑和週期無法做一點讓它變得更好。 – 2009-10-30 10:26:27

1

考慮員工的表:

CREATE TABLE Employee 
(
    EmpID INTEGER NOT NULL PRIMARY KEY, 
    Name VARCHAR(40) NOT NULL, 
    MgrID INTEGER NOT NULL REFERENCES Employee(EmpID) ON DELETE CASCADE 
); 

INSERT INTO Employees( 1, "Bill", 1); 
INSERT INTO Employees( 23, "Steve", 1); 
INSERT INTO Employees(234212, "Helen", 23); 

現在假設比爾退休:

DELETE FROM Employees WHERE Name = "Bill"; 

Ooooppps;每個人都被解僱了!

[我們可以辯論語法的細節是否正確;我想這個概念是站得住腳的。]

+13

我認爲在這種情況下ON DELETE CASCADE使用不正確。對不起,如果你構建一個錯誤的程序,這是你自己的錯誤 - 編程語言的作用不是保護你不寫糟糕的代碼。 – 2009-10-30 10:21:33

-1

我認爲是否使用ON DELETE CASCADE選項是您正在實施的業務模型的問題。兩個業務對象之間的關係可以是一個簡單的「關聯」,關係的兩端是相關的,但是否則其他生命週期不同並且由其他邏輯控制的獨立對象。但是,也有「聚合」關係,其中一個對象實際上可能被視爲「子」或「細節」對象的「父」或「所有者」。有一種更強的「組合」關係的概念,其中一個對象完全作爲多個部分的組合存在。 在「關聯」情況下,您通常不會聲明ON DELETE CASCADE約束。但是,對於聚合或合成,ON DELETE CASCADE可幫助您更準確地以聲明方式將業務模型映射到數據庫。 這就是爲什麼它讓我煩惱,MS SQL Server將此選項的使用限制爲單個級聯路徑。如果我沒有弄錯,許多其他廣泛使用的SQL數據庫系統不會施加這樣的限制。

+0

這是一個答案...怎麼樣? – 2010-10-27 15:50:08

1

我認爲問題在於,如果將一個路徑設置爲「ON DELETE CASCADE」,而另一個「ON DELETE RESTRICT」或「NO ACTION」,則結果(結果)無法預測。它取決於哪個刪除觸發器(這也是一個觸發器,但不需要自己構建)將首先執行。

+0

對於交易,這應該不是問題 - 行被刪除,刪除級聯,然後刪除被限制,整個事情回滾。 – Brilliand 2014-01-27 19:12:06