我有執行的TableB
一個聯接到一個TableA
存儲過程:SQL Server死鎖修復:強制連接命令或自動重試?
SELECT <--- Nested <--- TableA
Loop <--
|
---TableB
與此同時,在交易中,行插入TableA
,然後進入TableB
。
這種情況偶爾會造成死鎖,因爲存儲過程中選擇待價而沽行從表B,而插入添加行表A,然後每個人都希望對方讓對方表的走:
INSERT SELECT
========= ========
Lock A Lock B
Insert A Select B
Want B Want A
....deadlock...
邏輯要求INSERT
到第一行添加到一個,然後乙,而我個人不喜歡在SQL Server執行其加入的順序 - 只要它加入。
修復死鎖的常見建議是確保每個人都以相同的順序訪問資源。但在這種情況下,SQL Server的優化器告訴我,相反的順序是「更好」。我可以強制另一個連接順序,並有一個更糟糕的執行查詢。
但我應該嗎?
我應該重寫優化器,現在和永遠,我想要它使用的連接順序?
或者我應該只是捕獲錯誤本地錯誤1205,並重新提交select語句?
問題是,當我重寫優化程序併爲它做非最優化的事情時,查詢可能執行的程度會有多糟糕。問題是:自動重試更好,而不是運行更糟糕的查詢?
Remus, 重試讀取非常合理,但在死鎖後自動重試寫入會導致丟失更新。當你寫入併成爲死鎖受害者時,你接觸到的數據可能會被其他人修改。在這種情況下,我們不應該自動重寫。我們應該重新讀取可能修改的數據,並再次考慮是否要保存。說得通? – 2010-03-05 01:30:36
@AlexKuznetsov:這很荒唐,如果一個事務被正確地寫入(即自動),那麼如何重試它可能導致丟失的更新?我給這個+1,這絕對是正確的答案。你無法阻止每一個死鎖,它只是帶有ACID語義的背景噪聲的一部分。 – Aaronaught 2010-03-05 01:43:51
@Alex,@Aaro:你其實都是對的。通過「重試」,我的意思確實是「讀取當前狀態,應用更改,寫回新狀態」。對於自動化處理應用程序,這是一個非常容易實現的模式。但是,對於用戶交互式應用程序來說,這可能比較困難,通常適當的操作是通過重新讀取當前狀態並將其重新顯示給用戶來推回「寫入」,以便他/她可以確認應用的更改在新的狀態/背景下有意義,我認爲這就是Alex想到的。因此,正確的行動依情況而定。 – 2010-03-05 01:55:46