搜索

sqlserver查死锁语句

发表于 2026-10-17 02:26:32 来源:烟消火灭网

SQL Server 里出现死锁,死锁第一反应不该是语句重启服务。重启能暂时缓解,死锁但根因还在,语句过半小时又堵上了。死锁我见过一个订单系统,语句每天下午两点准时卡死,死锁DBA 重启了三天,语句第四天终于有人想起来查一下死锁日志——结果是死锁一个批量更新和单条插入在同一个索引页上互不相让。所以关键不是语句“怎么杀掉死锁”,而是死锁“怎么看到死锁长什么样”。

最直接的语句办法,是死锁开跟踪标志 1222。它会把死锁的语句详细信息写进 SQL Server 错误日志。执行下面这句,死锁立刻生效,不用重启:

DBCC TRACEON(1222, -1);

那个 -1 表示对所有连接生效。之后一旦发生死锁,你打开 SSMS 的“管理 → SQL Server 日志”,就能看到类似这样的内容:

deadlock-list deadlock victim=process1 process-list process id=process1 ... executionStack frame procname=adhoc line=1 ... inputbuf UPDATE Orders SET Status=2 WHERE OrderId=1001 process id=process2 ... inputbuf INSERT INTO OrderLog ... resource-list pagelock fileid=1 pageid=1234 ... owner-list owner id=process2 mode=X waiter-list waiter id=process1 mode=IX 

这段文本比任何图形化工具都可靠。它告诉你两件事:谁被选为牺牲品(victim),以及双方各自在等什么资源。上面这个例子,process1 想拿页上的 IX 锁,但 process2 已经持有 X 锁不放;而 process2 又在等 process1 手里的另一个资源——环就这么形成了。

如果你不想动服务器级别的跟踪标志,也可以用扩展事件。SQL Server 2008 以后都支持,开销小,还能把死锁图存成 XML 文件。建一个会话:

CREATE EVENT SESSION [DeadlockCapture] ON SERVER ADD EVENT sqlserver.xml_deadlock_report ADD TARGET package0.event_file ( SET filename = N'D:\Deadlock\deadlock.xel' ) WITH (MAX_DISPATCH_LATENCY = 5 SECONDS); GO ALTER EVENT SESSION [DeadlockCapture] ON SERVER STATE = START; 

跑一段时间后,用下面这句读文件:

SELECT XEventData.XEvent.value('(data/value)[1]', 'varchar(max)') AS DeadlockGraph FROM ( SELECT CAST(target_data AS XML) AS TargetData FROM sys.dm_xe_session_targets AS t JOIN sys.dm_xe_sessions AS s ON t.event_session_address = s.address WHERE s.name = 'DeadlockCapture' AND t.target_name = 'event_file' ) AS Data CROSS APPLY TargetData.nodes('//RingBufferTarget/event') AS XEventData(XEvent); 

拿到的 DeadlockGraph 是一段 XML,SSMS 里点一下就能展开成图形。两个椭圆、几根箭头,谁等谁一目了然。我一般会把它另存为 .xdl 文件,下次开会直接拖进 SSMS 展示,比嘴解释快得多。

还有种偷懒但管用的办法:查 sys.dm_tran_locks 和 sys.dm_exec_requests 的关联。死锁发生的瞬间你未必抓得住,但如果有持续阻塞,这两个视图能告诉你谁在等、等什么锁、等多久。比如:

SELECT request_session_id, resource_type, resource_description, request_mode, request_status FROM sys.dm_tran_locks WHERE request_status = 'WAIT';

看到 WAIT 的行,再去 sys.dm_exec_requests 里找对应的 blocking_session_id,顺藤摸瓜。不过这只对阻塞有效,真正的死锁已经被 SQL Server 自动选一个牺牲品杀掉了,所以还是得靠 1222 或扩展事件留痕。

说个真实教训。有次生产库死锁,我开了 1222,等了半天没复现。后来发现是应用层用了 NOLOCK 提示,读脏数据导致逻辑错乱,反过来又去更新同一批行。死锁日志里根本看不到 NOLOCK 的影子,因为那是隔离级别的事。所以查死锁语句只是第一步,看到语句之后还得结合执行计划、索引碎片、事务隔离级别一起看。光盯着 UPDATE 和 INSERT 互相等,容易漏掉真正的元凶。

最后提醒一句:1222 跟踪标志对性能几乎没影响,但错误日志会膨胀。查完记得关掉:DBCC TRACEOFF(1222, -1);。扩展事件会话也一样,不用了就 ALTER EVENT SESSION ... STATE = STOP;,别让它一直写磁盘。

随机为您推荐
友情链接
版权声明:本站资源均来自互联网,如果侵犯了您的权益请与我们联系,我们将在24小时内删除。

Copyright © 2016 Powered by sqlserver查死锁语句,烟消火灭网   sitemap

回顶部