概述 最近遇到一個生產環境的問題,報錯如下: 事務(行程 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調整下索引,使其更新時走索引查找,最后解決此問題,
如果遇到死鎖的問題,分析了代碼,的確沒問題,可以考慮導致死鎖的陳述句會不會有性能問題,從索引著手,
轉載請註明出處,本文鏈接:https://www.uj5u.com/shujuku/243219.html
標籤:SQL Server
