[分享]怎么捕获和记录SQL Server中发生的死锁?

coleling 2010-12-20 02:13:31
加精
经带在论坛上看到有人在问怎么捕获和记录死锁信息,在这里,我将自己的一些心得贡献出来,与大家分享,也请各位指正。

我们知道,可以使用SQL Server自带的Profiler工具来跟踪死锁信息。但这种方式有一个很大的敝端,就是消耗很大。据国外某大神测试,profiler甚至可以占到服务器总带宽的35%,所以,在一个繁忙的系统中,使用profiler显然不是一个好主意,下面我介绍两种消耗比较少的方法。其中第二种的消耗最小,在最繁忙的系统中也可使用。第一种最为灵活,可满足多种应用。

方法一:利用SQL Server代理(Alert+Job)

具体步骤如下:

1.首先使用下面的命令,将有关的跟踪标志启用。

DBCC TRACEON (3605,1204,1222,-1)  


说明:
3605 将DBCC的结果输出到错误日志。
1204 返回参与死锁的锁的资源和类型,以及受影响的当前命令。
1222 返回参与死锁的锁的资源和类型,以及使用了不符合任何 XSD 架构的 XML 格式的受影响的当前命令(比1204更进一步,SQL 2005及以上可用)。
-1 以全局方式打开指定的跟踪标记。

以上跟踪标志作用域都是全局,即在SQL Server运行过程中,会一直发挥作用,直到SQL Server重启。

如果要确保SQL Server在重启后自动开启这些标志,可以在SQL Server服务启动选项中,使用 /T 启动选项指定跟踪标志在启动期间设置为开。(位于SQL Server配置管理器->SQL Server服务->SQL Server->属性->高级->启动参数)

在运行上面的语句后,当SQL Server中发生死锁时,已经可以在错误日志中看到了,但还不够直观(和其它信息混在一起)。(SSMS -> SQL Server实例 -> 管理 -> SQL Server日志)

2.建表,存放死锁记录

USE [Cole] --Cole是我的示例数据库,你可以根据实际情况修改。  
GO
CREATE TABLE DeadLockLog (
id int IDENTITY (1, 1) NOT NULL,
LogDate DATETIME,
ProcessInfo VARCHAR(10),
ErrorText VARCHAR(MAX)
)
GO



3.建立JOB

新建一个JOB(假设名称为DeadLockJob),在"步骤"中新建一步骤,随便写一个步骤名称,数据库为"Cole"(见2.建表),在"命令"栏中输入以下语句:

--新建临时表  
IF OBJECT_ID('tempdb.dbo.#ErrorLog') IS Not Null
DROP TABLE #ErrorLog

CREATE TABLE #ErrorLog (Id int IDENTITY (1, 1) NOT NULL, a DATETIME, b VARCHAR(10), c VARCHAR(MAX))

--将当前日志记录插入临时表
INSERT INTO #ErrorLog EXEC master.dbo.sp_readerrorlog

--将死锁信息插入用户表
insert DeadLockLog
select a, b, c
from #ErrorLog
where id >= (select MAX(id) from #ErrorLog WHERE c Like '%Deadlock encountered%')

DROP TABLE #ErrorLog


4.新建警报

在"新建警报"窗体的"常规"选项卡中,进行以下设置:

名称:可根据实际自行命名,这里我用DeadLockAlert
类型:选择"SQL Server性能条件警报"
对象:SQLServer:Locks
计数器:Number of Deadlocks/sec
实例:_Total
计数器满足以下条件时触发警报:高于
值:0

设置完成后,应该如下图所示:


在"响应"选项卡中,选中"执行作业",并选择步骤3中我们新建的作业(即DeadlockJob)

到这里为止,我们已经完成了全部步骤,以后,你就可以随时查询DeadLockLog表,来显示死锁信息了。

方法二:利用服务器端跟踪。

具体实现步骤如下:

1.编写如下脚本,并执行

-- 定义参数  
declare @rc int
declare @TraceID int
declare @maxfilesize bigint
set @maxfilesize = 5

-- 初始化跟踪
exec @rc = sp_trace_create @TraceID output, 0, N'e:\DbLog\deadlockdetect', @maxfilesize, NULL
--此处的e:\dblog\deadlockdetect是文件名(可自行修改),SQL会自动在后面加上.trc的扩展名
if (@rc != 0) goto error

-- 设置跟踪事件
declare @on bit
set @on = 1
--下述语句中的148指的是locks:deadlock graph事件(参见sys.trace_events),12指的是spid列(参见sys.trace_columns)
exec sp_trace_setevent @TraceID, 148, 12, @on
exec sp_trace_setevent @TraceID, 148, 11, @on
exec sp_trace_setevent @TraceID, 148, 4, @on
exec sp_trace_setevent @TraceID, 148, 14, @on
exec sp_trace_setevent @TraceID, 148, 26, @on
exec sp_trace_setevent @TraceID, 148, 64, @on
exec sp_trace_setevent @TraceID, 148, 1, @on

-- 启动跟踪
exec sp_trace_setstatus @TraceID, 1

-- 记录下跟踪ID,以备后面使用
select TraceID = @TraceID
goto finish

error:
select ErrorCode=@rc

finish:
go


运行上述语句后,每当SQL Server中发生死锁事件,都会自动往文件e:\DbLog\deadlockdetect.trc中插入一条记录。

2.暂停和停止服务器端跟踪

如果要暂停上面的服务器端跟踪,可运行下面的语句:

exec sp_trace_setstatus 1, 0 --第一个参数表示TraceID,即步骤1中的输出参数。第二个参数表示将状态改为0,即暂停


如果要停止上面的服务器端跟踪,可运行下面的语句:

exec sp_trace_setstatus 1, 2 --第一个参数表示TraceID,即步骤1中的输出参数。第二个参数表示将状态改为2,即停止


3.查看跟踪文件内容

对于上面生成的跟踪文件(e:\DbLog\deadlockdetect.trc),可通过两种方法查看:

1).执行t-sql命令

select * from fn_trace_gettable('e:\DbLog\deadlockdetect.trc',1)  


结果中的TextData列即以XML的形式返回死锁的详细信息。

2).在SQL Server Profiler中打开。

依次 进入Profiler -> 打开跟踪文件 ->选择e:\DbLog\deadlockdetect.trc,就可以看到以图形形式展现的死锁信息了。
...全文
3829 190 打赏 收藏 转发到动态 举报
写回复
用AI写文章
190 条回复
切换为时间正序
请发表友善的回复…
发表回复
newchenj 2011-02-28
  • 打赏
  • 举报
回复
先收了,以后再研究.
咿呀大河马 2010-12-31
  • 打赏
  • 举报
回复
谢谢LZ分享!
「已注销」 2010-12-31
  • 打赏
  • 举报
回复
收藏……
CNFIVE 2010-12-30
  • 打赏
  • 举报
回复
123456
ring2004 2010-12-29
  • 打赏
  • 举报
回复
好帖收藏了,以前的单位就没能解决死锁的问题,希望以后遇到了能有所帮助
呼特李一号 2010-12-28
  • 打赏
  • 举报
回复
010101010101
唐诗三百首 2010-12-28
  • 打赏
  • 举报
回复
[Quote=引用 181 楼 sx54605628 的回复:]
对于死锁的解决方法帖子有很多,但似乎还是有很多人在问
[/Quote]
我讲D是预防方法,问题预防比问题解决更重要.
sx54605628 2010-12-27
  • 打赏
  • 举报
回复
对于死锁的解决方法帖子有很多,但似乎还是有很多人在问
Teng_s2000 2010-12-26
  • 打赏
  • 举报
回复
zlcp520 2010-12-24
  • 打赏
  • 举报
回复
容存入剪贴板
唐诗三百首 2010-12-24
  • 打赏
  • 举报
回复
请教楼主一个问题,所谓死锁(Dead Lock),可否举例说明一下.
大学学过<操作系统>里的死锁,不知跟数据库里是否相同概念.

例如,连线1持有A表的排他锁(X Lock),连线2持有B表的排他锁(X Lock).
连线1现在欲修改B表,申请B表的X锁,等待...
连线2现在欲修改A表,申请A表的X锁,也等待...
请问以上就是死锁的一般情况吗?除了被跟踪出来后人工KILL进程来解锁.
是否还有其他更好的解决方法,在写事务的时候?也就是怎样避免此类问题的发生?
haa17 2010-12-24
  • 打赏
  • 举报
回复
给力啊
Dogfish 2010-12-24
  • 打赏
  • 举报
回复
值得学习。
Harmony_liu 2010-12-24
  • 打赏
  • 举报
回复
如果使用SQL Server 2005/2008, 可以用以下script执行,轻易找到session_id和blocking_session_id:
SELECT DB_NAME(r.database_id), r.session_id, r.blocking_session_id, s.program_name, s.host_name,
r.wait_time,r.wait_type, r.start_time, r.status,r.command
FROM sys.dm_exec_requests r
INNER JOIN sys.dm_exec_sessions s ON r.session_id = s.session_id
WHERE s.is_user_process = 1
liangtiana 2010-12-24
  • 打赏
  • 举报
回复
毛好的类
山书生 2010-12-23
  • 打赏
  • 举报
回复
强力技术贴呀!!!
Gingk0 2010-12-23
  • 打赏
  • 举报
回复
经带在论坛上看到有人在问怎么捕获和记录死锁信息,在这里,我将自己的一些心得贡献出来,与大家分享,也请各位指正。
taiyan521777 2010-12-23
  • 打赏
  • 举报
回复
有关的东西我们下学期学
ShenWong 2010-12-23
  • 打赏
  • 举报
回复
收藏!
沧海遗珠 2010-12-23
  • 打赏
  • 举报
回复
首先祝贺,然后,楼主,贴点儿代码出来,让我们see一see,学一学啊。
加载更多回复(80)

22,297

社区成员

发帖
与我相关
我的任务
社区描述
MS-SQL Server 疑难问题
社区管理员
  • 疑难问题社区
  • 尘觉
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧