在数据库操作中,死锁是一个不可避免的问题。当遇到死锁,但却不知道谁是受害者和谁是肇事者时,情况会变得更加复杂。本文将介绍两种捕获和分析死锁的方法:启用跟踪标志将死锁信息记录到SQL日志中,以及使用SQL Profiler捕获死锁。
这种方法可以确保死锁的详细信息被记录在SQL日志文件中(不是事务日志)。虽然通过这种方法捕获的详细信息是文本形式的,但它允许稍后检查这些细节。
首先,需要使用以下语法启用跟踪标志:
DBCC TRACEON (1222, 1204, -1);
接下来,将模拟一个死锁(实际上,如果遇到这样的问题,不需要这样做)。
首先,创建两个示例表,并插入一些记录,将使用这些记录来产生死锁。
CREATE TABLE SampleDeadLock_1 (
Item_Code INT,
Item_Desc VARCHAR(100),
Qty INT
);
CREATE TABLE SampleDeadLock_2 (
Item_Code INT,
Item_Desc VARCHAR(100),
Qty INT
);
INSERT INTO dbo.SampleDeadLock_1 (Item_Code, Item_Desc, Qty) VALUES (1, 'CPU', 10), (2, '20 GB - Hard Disk', 20);
INSERT INTO dbo.SampleDeadLock_2 (Item_Code, Item_Desc, Qty) VALUES (3, 'Monitor', 15), (4, 'Keyboard & Mouse', 25);
现在,在SQL ServerManagement Studio中打开两个查询窗口(窗口1和窗口2),并将以下代码粘贴到“窗口1”:
BEGIN TRAN;
UPDATE dbo.SampleDeadLock_1 SET Qty = 100 WHERE Item_Code = 1;
WAITFOR DELAY '00:00:30';
UPDATE dbo.SampleDeadLock_2 SET Qty = 200 WHERE Item_Code = 3;
并将以下代码粘贴到“窗口2”:
BEGIN TRAN;
WAITFOR DELAY '00:00:10';
UPDATE dbo.SampleDeadLock_2 SET Qty = 300 WHERE Item_Code = 3;
UPDATE dbo.SampleDeadLock_1 SET Qty = 400 WHERE Item_Code = 1;
之后,在窗口1执行代码,然后立即在窗口2执行代码。几秒钟后(30+),将在窗口1看到一个死锁错误消息。当检查ERRORLOG文件时,将能够找到与死锁相关的详细信息。(已经用红色突出显示了死锁受害者的详细信息,用蓝色突出显示了肇事者详细信息。)
在前述方法中,面临的一个问题是,需要查看大量的文本信息以提取与死锁相关的详细信息。在这个例子中,由于选择了一个简单的情况,所以相对容易。但在实际情况中,当进程更加复杂时,事情可能会变得非常困难。
在这种情况下(任何情况下),可以使用SQL Profiler以更用户友好的方式检测死锁。
**请注意:这种方法的缺点是需要在死锁发生时运行分析器。如果需要在生产环境中进行故障排除,这不是最好的方法。
然而,为了理解,将看看如何实现这一点。
打开SQL Profiler并连接到相关的SQL Server。在“跟踪属性”窗口中,选择“TSQL_Locks”作为模板。
在“事件选择”选项卡中,请选择以下选项:
在点击运行分析器之前,回滚第一个示例中正在运行的事务(没有成为死锁受害者的那个)。
通过点击“运行”按钮启动分析器。一旦分析器运行,执行查询窗口1中的代码,然后执行查询窗口2中的代码。