前些天,同事遇到一個死鎖的問題,走過去看看,一下子不知道怎么寫,又想起三年前面試的時候問的一個with(nolock)相關的問題,忙活了一會,弄出個東東
核心主要是視圖sys.SysProcesses,它源自於系統表sysprocesses,前者是微軟推薦的用法,因為后者在未來SQL Server版本中可能會被隱藏。視圖字段含義見這里。然后是kill 命令,它加上進程id就可以殺掉相應進程,它的簡單用法如下:

1 use Test 2 go 3 -- 列出所有進程信息 4 EXEC sp_who2 5 go 6 7 -- 執行殺掉進程命令 8 KILL 29 9 go
准備工作:
1.

1 CREATE TABLE TestDead 2 ( 3 id INT IDENTITY(1,1) PRIMARY KEY, 4 name NVARCHAR(10) NOT NULL 5 ) 6 GO 7 8 CREATE TABLE TestDead2 9 ( 10 id INT IDENTITY(1,1) PRIMARY KEY, 11 name NVARCHAR(10) NOT NULL 12 ) 13 GO 14 15 INSERT INTO TestDead(name) 16 VALUES ('name01'), 17 ('name02'), 18 ('name03') 19 GO 20 21 INSERT INTO TestDead2(name) 22 VALUES ('name01'), 23 ('name02'), 24 ('name03') 25 GO 26 27 BEGIN TRAN -- 打開一個更新事務,不提交, 鎖住第一個表 28 29 UPDATE TestDead SET name = 'nameXX' WHERE id = 1 30 31 GO 32 33 34 BEGIN TRAN --開始一個事務,不提交,鎖住第二個表 35 36 UPDATE TestDead2 SET name = 'nameXX' WHERE id = 1 37 38 GO
2. 創建了表之后,開始一個更新數據的事務並鎖住了表,然后新建多個查詢窗口,在各個不同窗口中,分別執行下面兩條語句:

1 -- 查詢第一個表 2 3 select * from TestDead 4 5 6 -- 查詢第二個表 7 8 select * from TestDead2
3. 現在由於表被鎖住,是查詢不出數據,除非在后面加上 with(nolock),如:

1 select * from TestDead2 with(nolock)
列出並殺掉那些死鎖的進程:
1 ============================================= 2 -- Author: Mike Deng 3 -- Create date: 2014/05/14 4 -- Description: 殺掉死鎖進程 5 ============================================= 6 7 DECLARE @toKill BIT = 0 --0 或 NULL 只顯示, 1.殺掉 8 9 BEGIN 10 DECLARE @sql NVARCHAR(MAX); 11 DECLARE @fromSql NVARCHAR(MAX); 12 13 SET @fromSql = ' 14 DECLARE @cmd NVARCHAR(MAX); 15 ;with CTE as( 16 SELECT distinct Type = ''死鎖的進程'' 17 , a.spid 18 , blockId = 0 19 , DBName = DB_NAME(a.dbid) 20 , a.HostName 21 , ProgramName = a.Program_Name 22 , Dead = 1 23 FROM SYS.SYSPROCESSES a JOIN 24 SYS.SYSPROCESSES as b ON a.spid = b.blocked 25 WHERE a.blocked = 0 26 UNION ALL 27 SELECT distinct Type = ''被阻塞進程'' 28 , a.spid 29 , blockId = a.blocked 30 , DBName = DB_NAME(a.dbid) 31 , a.HostName 32 , ProgramName = a.Program_Name 33 , Dead = 0 34 FROM SYS.SYSPROCESSES a WHERE blocked <> 0 35 ) ' 36 37 IF(ISNULL(@toKill, 0) = 1) 38 BEGIN 39 SET @sql = @fromSql 40 + 'SELECT @cmd = ( 41 SELECT ('' KILL '' + LTRIM(str(spid))) FROM cte WHERE dead = 1 42 FOR XML PATH('''') 43 ) 44 IF(ISNULL(@cmd, '''') <> '''') 45 BEGIN 46 EXEC (@cmd); 47 PRINT ''已執行kill死鎖命令【'' + @cmd + ''】, 鎖已解除''; 48 END 49 ELSE IF(@@RowCount = 0) 50 BEGIN 51 PRINT ''未發現死鎖, 不能殺掉''; 52 END' 53 END 54 ELSE 55 BEGIN 56 SET @sql = @fromSql + ' SELECT * FROM cte '; 57 END 58 59 EXEC SP_EXECUTESQL @sql 60 END
查詢結果:
設置參數 @toKill = 1,殺掉它們。
完工!