專案上線後網站突然無法訪問,重啟主機暫時恢復,排查發現是高併發修改同一條 Stat 表記錄導致死鎖與阻塞。
USE master
GO
DECLARE @spid INT, @bl INT
DECLARE s_cur CURSOR FOR
SELECT 0, blocked FROM (SELECT * FROM sysprocesses WHERE blocked > 0) a
WHERE NOT EXISTS (SELECT * FROM (SELECT * FROM sysprocesses WHERE blocked > 0) b WHERE a.blocked = spid)
UNION
SELECT spid, blocked FROM sysprocesses WHERE blocked > 0
OPEN s_cur
FETCH NEXT FROM s_cur INTO @spid, @bl
WHILE @@FETCH_STATUS = 0
BEGIN
IF @spid = 0
SELECT '引發死鎖的進程: ' + CAST(@bl AS VARCHAR(10)) + ',其 SQL 如下'
ELSE
SELECT 'SPID: ' + CAST(@spid AS VARCHAR(10)) + ' 被 SPID: ' + CAST(@bl AS VARCHAR(10)) + ' 阻塞,當前 SQL 如下'
DBCC INPUTBUFFER(@bl)
FETCH NEXT FROM s_cur INTO @spid, @bl
END
CLOSE s_cur
DEALLOCATE s_cur
EXEC sp_who2
創建 p_lockinfo,支持參數控制:是否殺掉死鎖進程、無死鎖時是否顯示正常進程。
CREATE PROC p_lockinfo
@kill_lock_spid BIT = 1, -- 1=殺掉死鎖進程
@show_spid_if_nolock BIT = 1 -- 1=無死鎖時顯示正常進程
AS
BEGIN
-- 將死鎖進程與受害者進程寫入臨時表 #t
-- 循環執行 DBCC INPUTBUFFER 獲取 SQL 文本
-- @kill_lock_spid=1 時自動 KILL 死鎖 SPID
-- 最後輸出進程信息與對應 SQL
END
GO
調用示例: EXEC p_lockinfo(默認殺掉死鎖並顯示詳情)。