SQL Server死鎖報錯分析

概述
最近遇到一個生產環境的問題,報錯以下:
事務(進程 ID 89)與另外一個進程被死鎖在 鎖 資源上,而且已被選做死鎖犧牲品。請從新運行該事務。
拉取了請求日誌,該接口有併發的請求,在同一時刻,有多個請求。分析了下代碼,主要的部分是包裹在事務中,且給主要的數據更新加了數據庫資源鎖。可見
https://docs.microsoft.com/en-us/sql/relational-databases/system-stored-procedures/sp-getapplock-transact-sql?view=sql-server-ver15
但最後仍是報了上面的錯誤。
分析
首先,這個報錯,是數據庫級別的報錯。代碼層面,看了幾遍代碼,考慮了各個場景並無問題。也就是說,是在數據庫中更新表的時候,SQL SERVER報錯了。報錯時有抓到報錯的語句,分析了下,是更新某張表的字段時,報錯的。一開始一直在分析代碼層面,可是始終沒思路。後臺和同事分析了下報錯的SQL語句。有這麼一個問題,若是,在一個事務內,對錶加了鎖,可是這個更新比較慢,查看執行計劃走的時候索引掃描;而這個時候有併發的狀況,全部的請求都要執行這段更新的語句,那麼就有問題了。以下
請求1更新時有必定的更新時間,併發請求2,3,4,5來了,那麼都會排隊,並且須要select 查詢更新的table以及其餘的資源,而請求1也會查詢其它請求鎖 鎖住資源。一旦更新時間長,且SQL阻塞了,就會有死鎖的問題。
解決
既然是SQL更新問題,那麼第一查看的應該是索引。看了下索引,的確有關於這段更新SQL的索引,可是更新的字段順序不對,致使走的時候索引掃描,而不是索引查找。知足索引查找的通常性結論:若是條件中包含WHERE或者ON的話,查詢條件必須是位於索引集合列中首位,輸出列排在其次,此時索引查找將會被使用。
where、on 關鍵字後面的字段要加上索引,通常建議是 過濾字段加索引,輸出字段在Include中維護。以下示例
CREATE INDEX ix_roomguids_status_tradeguid
ON dbo.s_Booking (RoomGUIDs, Status, tradeguid)
INCLUDE (ProjGUID, CloseReason);

CREATE INDEX ix_tradestatus_roomstatus
ON s_Trade (TradeStatus, RoomStatus)
INCLUDE (ZcOrderGUID, CloseReason);


SELECT      s_Trade.TradeGUID,
            dbo.s_Trade.RoomStatus,
            t.ProjGUID,
            t.CloseReason,
            s_Trade.ZcOrderGUID,
            dbo.s_Trade.CloseReason
  FROM      (   SELECT *
                  FROM dbo.s_Booking
                 WHERE RoomGUIDs IS NOT NULL
                   AND Status = '關閉') t
 INNER JOIN dbo.s_Trade
    ON s_Trade.TradeGUID = t.TradeGUID
   AND TradeStatus       = '激活'
   AND RoomStatus        = '認購';
輸出結果
因此,給更新的SQL調整下索引。使其更新時走索引查找。最後解決此問題。
若是遇到死鎖的問題,分析了代碼,的確沒問題。能夠考慮致使死鎖的語句會不會有性能問題,從索引着手。
相關文章
相關標籤/搜索