2010-05-31 65 views
5

我在ASP.NET MVC/SQL Server中有一個非常流行的網站,不幸的是發生了很多死鎖。當我試圖找出它們爲什麼通過SQL分析器發生時,我想知道如何在執行死鎖時更改SQL Server的默認行爲。如何自動重新運行死鎖事務? (ASP.NET MVC/SQL Server)

是否有可能重新運行導致問題的事務而不是顯示錯誤屏幕?

回答

6

你在吠叫錯誤的樹。您將永遠不會成功通過SQL引擎執行自動死鎖重試,這種概念從根本上說是錯誤的。死鎖的定義是,你根據你決定的狀態已更改因此你需要再次閱讀狀態並作出新的決定。如果你的過程已經死鎖,根據定義,另一個過程有贏得的死鎖,並且它已經測量了已更改你讀過的東西。

你的只有重點應該在弄清楚爲什麼發生死鎖並消除原因。不變的是,原因將變成查詢,掃描更多的數據,他們應該。雖然其他類型的僵局可能會發生,但我敢打賭你不是這樣。通過部署適當的索引可以解決很多問題。有些問題會讓你回到繪圖板,你將不得不重新考慮你的要求。

有很多,很多資源在那裏就如何識別和解決死鎖:

您也可以考慮使用快照隔離,因爲無鎖涉及快照的讀取減少了可能發生死鎖的表面(即,只有寫 - 寫死鎖可能發生)。請參閱Using Row Versioning-based Isolation Levels

+0

@Mitch:任何重試邏輯必須位於*應用程序*中。我的觀點是,你不能讓SQL Server自己記錄你的事務,併爲你重新嘗試。 – 2010-05-31 17:08:42

2

發生很多死鎖通常表示您沒有正確的索引和/或您的統計信息已過期。作爲維護的一部分,您是否定期進行索引重建?

當保存代碼在返回錯誤1205(發生死鎖)時應自動重試保存。有一個標準模式,看起來像這樣:

catch (SqlException ex) 
{ 
    if (ex.Number == 1205) 
    { 
     // Handle Deadlock by retrying save... 
    } 
    else 
    { 
     throw; 
    } 
} 

另一個選項是在您的存儲過程中重試。這裏有一個例子:Using TRY...CATCH in Transact-SQL

+0

是的,我知道:我的邏輯必然存在一個小故障。但問題是如何改變服務器的行爲? – Alex 2010-05-31 03:39:05

+1

他不是說你的代碼不好。他說你應該檢查數據庫中表格的索引,並重新創建它們或者添加新的索引。 – 2010-05-31 03:59:59

+0

好的...然後是另一個問題。假設頁面A發生死鎖,但頁面B正試圖訪問鎖定的數據。錯誤將顯示在頁面B上,但並不意味着頁面B上發生了死鎖。它仍然出現在頁面A上。 對不起,如果這很愚蠢,我很難理解這個概念。 – Alex 2010-05-31 04:21:28

1

除了Mitch和Remus提出的建議之外,還有一種選擇,因爲您的意見建議您尋求快速修復。如果可以識別死鎖中涉及的查詢,則可以通過爲每個查詢,批處理或存儲過程設置DEADLOCK_PRIORITY來影響涉及哪些查詢回滾以及哪些查詢繼續。在你的榜樣

展望米奇的答案的評論:

比方說,發生死鎖第A, 但網頁B試圖訪問 鎖定的數據。錯誤將是頁面B上顯示的 ,但它不是 意味着頁面B上的 發生了死鎖。它仍然出現在頁面A上。

如果您始終發現從頁面A和頁面B發出的查詢中發生死鎖,則可以影響哪個頁面導致錯誤並且哪個頁面成功完成。正如其他人所說的,你不能自動強制重試。

發佈有問題的查詢和/或死鎖跟蹤輸出的問題,您很可能會得到一個解釋,說明它爲什麼會發生以及如何修復。

+0

謝謝。問題是死鎖發生在存儲過程中。 SQL事件探查器顯示該過程的名稱,但我無法在發生它的位置獲取該查詢,並且在那裏有很多查詢。如何追蹤問題發生在哪個查詢中? – Alex 2010-05-31 12:55:37

+1

您可以啓用跟蹤標誌1204和1222,這兩個標誌都包含在鏈接的「檢測和死鎖」文章Remus中。這會給你詳細的查詢和哪些資源。將報告涉及的行,頁面,索引或表以及每個進程所需的鎖的類型。從這裏,你可能能夠確定一個修復程序,否則發佈一個問題與死鎖蹤跡和死鎖過程的來源。 您是否無法修改發生問題的存儲過程? – 2010-05-31 14:30:16

+0

不,我可以修改SP。我會看看這篇文章,並啓用標誌。希望它會起作用。 – Alex 2010-05-31 14:37:01

10

Remus's answer是根本上有缺陷。根據https://stackoverflow.com/a/112256/14731,一致的鎖定順序不會防止死鎖。我們能做的最好的是減少他們的頻率。

他錯了兩點:

  1. 的死鎖可以預防的含義。您將會發現微軟和IBM發佈的關於減少死鎖頻率的文章。沒有他們聲稱你可以完全防止他們。
  2. 暗示全部死鎖要求您重新評估狀態並做出新的決定。在應用程序級別重試某些操作是完全正確的,只要您足夠回到決策點。

側面說明:Remus的主要觀點是,數據庫不能自動重試以您的名義運作,他是對數完全正確。但這並不意味着重新運行操作對僵局的反應是錯誤的。

0

在某些情況下,您可以在下面執行操作。在開始tran和commit之間是全部或沒有。因此,@errorcode將0作爲值並結束循環,或者在出現故障時將計數器減1並再次重試。如果您從外部提供變量以開始tran/commit,則它可能不起作用。只是一個想法:)

declare @errorcount int = 4 -- retry number 
while @errorcount >0 
begin 
begin tran 
<your code here> 
set @errorcount =0 
commit 
set @[email protected] 
end 
相關問題