`p_lockinfo` 可:
CREATE PROCEDURE dbo.p_lockinfo
@kill_lock_spid bit = 0, -- 1=KILL 阻塞者, 0=僅顯示
@show_spid_if_nolock bit = 0 -- 1=無阻塞時顯示所有 SPID
AS
BEGIN
SET NOCOUNT ON;
-- 1. 偵測阻塞鏈:Bloker (blocked=0 但被其他 SPID blocked) + Victims (blocked<>0)
SELECT
ID = IDENTITY(int,1,1),
Flag = CASE WHEN a.blocked = 0 THEN N'阻塞者(Bloker)' ELSE N'|_受害者(Victim)>' END,
SPID = a.spid,
KPID = a.kpid,
BlockedBy = a.blocked,
DBID = a.dbid,
DBName = DB_NAME(a.dbid),
UID = a.uid,
LoginName = a.loginame,
CPU = a.cpu,
LoginTime = a.login_time,
OpenTran = a.open_tran,
Status = a.status,
HostName = a.hostname,
ProgramName = a.program_name,
HostProcess = a.hostprocess,
NTDomain = a.nt_domain,
NetAddress = a.net_address,
Sort1 = CASE WHEN a.blocked = 0 THEN a.spid ELSE a.blocked END,
Sort2 = CASE WHEN a.blocked = 0 THEN 0 ELSE 1 END
INTO #LockChain
FROM master..sysprocesses a
JOIN (
SELECT blocked FROM master..sysprocesses WHERE blocked <> 0 GROUP BY blocked
) b ON a.spid = b.blocked
WHERE a.blocked = 0
UNION ALL
SELECT
ID = IDENTITY(int,1,1),
Flag = N'|_受害者(Victim)>',
SPID = a.spid, KPID = a.kpid, BlockedBy = a.blocked,
DBID = a.dbid, DBName = DB_NAME(a.dbid), UID = a.uid,
LoginName = a.loginame, CPU = a.cpu, LoginTime = a.login_time,
OpenTran = a.open_tran, Status = a.status, HostName = a.hostname,
ProgramName = a.program_name, HostProcess = a.hostprocess,
NTDomain = a.nt_domain, NetAddress = a.net_address,
Sort1 = a.blocked, Sort2 = 1
FROM master..sysprocesses a
WHERE a.blocked <> 0
ORDER BY Sort1, Sort2;
DECLARE @Count int = @@ROWCOUNT, @i int = 1;
-- 2. 若無阻塞且要求顯示所有 SPID
IF @Count = 0 AND @show_spid_if_nolock = 1
BEGIN
INSERT #LockChain (Flag, SPID, KPID, BlockedBy, DBID, DBName, UID, LoginName,
CPU, LoginTime, OpenTran, Status, HostName, ProgramName,
HostProcess, NTDomain, NetAddress)
SELECT N'正常程序', spid, kpid, blocked, dbid, DB_NAME(dbid), uid, loginame,
cpu, login_time, open_tran, status, hostname, program_name,
hostprocess, nt_domain, net_address
FROM master..sysprocesses;
SET @Count = @@ROWCOUNT;
END
-- 3. 取得 INPUTBUFFER 並選擇性 KILL
IF @Count > 0
BEGIN
CREATE TABLE #InputBuffer (ID int IDENTITY(1,1), EventType nvarchar(30), Parameters nvarchar(4000), EventInfo nvarchar(max));
IF @kill_lock_spid = 1
BEGIN
DECLARE @SPID varchar(10), @Flag nvarchar(20);
WHILE @i <= @Count
BEGIN
SELECT @SPID = CAST(SPID AS varchar(10)), @Flag = Flag FROM #LockChain WHERE ID = @i;
INSERT #InputBuffer EXEC ('DBCC INPUTBUFFER(' + @SPID + ') WITH NO_INFOMSGS');
IF @Flag = N'阻塞者(Bloker)' EXEC ('KILL ' + @SPID);
SET @i += 1;
END
END
ELSE
BEGIN
WHILE @i <= @Count
BEGIN
DECLARE @Sql nvarchar(200);
SELECT @Sql = 'DBCC INPUTBUFFER(' + CAST(SPID AS varchar(10)) + ') WITH NO_INFOMSGS' FROM #LockChain WHERE ID = @i;
INSERT #InputBuffer EXEC (@Sql);
SET @i += 1;
END
END
-- 4. 輸出結果
SELECT
lc.Flag, lc.SPID, lc.KPID, lc.BlockedBy, lc.DBName, lc.LoginName,
lc.CPU, lc.LoginTime, lc.OpenTran, lc.Status, lc.HostName,
lc.ProgramName, lc.HostProcess, lc.NTDomain, lc.NetAddress,
ib.EventInfo AS [執行的SQL批次]
FROM #LockChain lc
JOIN #InputBuffer ib ON lc.ID = ib.ID
ORDER BY lc.ID;
END
END;
-- 僅偵測顯示 EXEC dbo.p_lockinfo 0, 1; -- 偵測並自動 KILL 阻塞者 (謹慎使用!) EXEC dbo.p_lockinfo 1, 0;
`p_lockinfo` 是經典 DBA 手工腳本,適合即時人工排查。生產環境應部署 **Extended Events 死鎖捕捉 + 持續阻塞監控 + 查詢優化** 的系統化方案,而非依賴自動 KILL。