杀掉那些死锁的进程

  前些天,同事遇到一个死锁的问题,走过去看看,一下子不知道怎么写,又想起三年前面试的时候问的一个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
View Code

 准备工作:

  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
View Code

  2. 创建了表之后,开始一个更新数据的事务并锁住了表,然后新建多个查询窗口,在各个不同窗口中,分别执行下面两条语句:

1 -- 查询第一个表
2 
3 select * from TestDead
4 
5 
6 -- 查询第二个表
7 
8 select * from TestDead2
View Code

  3. 现在由于表被锁住,是查询不出数据,除非在后面加上 with(nolock),如:

1 select * from TestDead2 with(nolock)
View Code

 

列出并杀掉那些死锁的进程:

 

 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,杀掉它们。

完工!

 

posted @ 2014-05-15 22:22  牛肉兄  阅读(2565)  评论(3编辑  收藏  举报