我在我的系统上捕获了一个死锁,(匿名)XML 输出如下:
<deadlock>
<victim-list>
<victimProcess id="processf4d9233468" />
</victim-list>
<process-list>
<process id="processf4d9233468" taskpriority="0" logused="0" waitresource="KEY: 6:72057594039631872 (d117f90e375f)" waittime="481" ownerId="840005340" transactionname="SELECT" lasttranstarted="2019-10-14T10:16:07.550" XDES="0xeec803db90" lockMode="S" schedulerid="16" kpid="7220" status="suspended" spid="145" sbid="0" ecid="0" priority="0" trancount="0" lastbatchstarted="2019-10-14T10:16:07.547" lastbatchcompleted="2019-10-14T10:16:07.550" lastattention="1900-01-01T00:00:00.550" clientapp=".Net SqlClient Data Provider" hostname="MYWEBSERVER" hostpid="4512" loginname="MyOtherLogin" isolationlevel="read committed (2)" xactid="840005340" currentdb="6" currentdbname="MyDB" lockTimeout="4294967295" clientoption1="671088672" clientoption2="128056">
<executionStack>
<frame procname="MyDB.MySchema.MyProc" line="13" stmtstart="670" stmtend="9106" sqlhandle="MYSQLHANDLE">
SELECT p.[Col25]
, p.Col1
, pId.Col2
, p.Col3
, p.Col4
, p.Col5
, CONVERT(VARCHAR(10),p.Col6,103)
, a.[Col7]
, a.[Col8]
, a.[Col9]
, a.[Col10]
, a.[Col11] …
Run Code Online (Sandbox Code Playgroud) 我们的应用程序时不时地(大约每周一次)遇到死锁。
罪魁祸首似乎是带有两个选择的查询。其中之一是出于性能原因填充临时表,另一个是具有许多连接的相对复杂的选择,以返回具有许多详细信息的所有约会的列表。我看到的关于第二个选择的唯一可能特别的地方是它包含一个自连接。二选查询始终是 SQL Server 死锁事件报告的一部分。
另一个查询是对同一个表的简单 DML 查询(插入或更新),尽管这并不总是相同的 DML 查询。这两个查询都以标准READ COMMITTED
隔离方式运行,而不是在显式事务中运行。
这两个查询大致如下(我已缩短它们以进行澄清)
DECLARE @futureAppointments TABLE(clientId int, StartDate date)
INSERT INTO @futureAppointments SELECT clientId, StartDate FROM Appointments where StartDate >= @startDate
SELECT *, (SELECT COUNT(*) FROM @futureAppointments fa WHERE fa.clientId = a.clientId AND fa.StartDate > a.StartDate)
FROM Appointments a
join b on a.fk_b = b.id
join c on a.fk_c = c.id
join Appointments d on c.somefield = d.anotherfield
WHERE a.StartDate >= @startDate AND a.StartDate <= @endDate
Run Code Online (Sandbox Code Playgroud)
UPDATE Appointments SET …
Run Code Online (Sandbox Code Playgroud) 有一个死锁 XDL 文件,其中列出了几个交换事件。不确定这些是好是坏,或者是什么导致了它们。是什么导致 SQL 死锁图中的交换事件?
<exchangeEvent id="Pipe12dfb4bc900" WaitType="e_waitPipeGetRow" nodeId="28">
<owner-list>
<owner id="process4a9ee4eca8" />
</owner-list>
<waiter-list>
<waiter id="process2612ca8" />
</waiter-list>
</exchangeEvent>
Run Code Online (Sandbox Code Playgroud) 我试图理解为什么 SQL Server (2014) 在死锁场景中放置独占键锁。我已将整个死锁图粘贴在下面。
我很困惑,因为死锁发生在两个 SELECT 语句之间,两者都作为单个 READ COMMITTED 语句运行,而不是在事务内运行(因此同一事务中的其他地方没有发生更新等)。
我相信发生死锁是因为每个进程都在索引上创建一系列键锁,并且由于获取它们的顺序,所以发生了死锁。但是,如果进程仅创建共享锁,则不应出现死锁(根据我的理解)!
所以根本问题是 - 为什么这些 SELECT 语句会获取独占键锁?
我希望这只是我对锁定的误解。任何建议将不胜感激。
<deadlock>
<victim-list>
<victimProcess id="processd7f647848" />
</victim-list>
<process-list>
<process id="processd7f647848" taskpriority="0" logused="25948" waitresource="KEY: 32:72057594051428352 (e2d15ad895e9)" waittime="5014" ownerId="394724294049" transactionname="user_transaction" lasttranstarted="2022-04-06T09:46:18.770" XDES="0x67bf873350" lockMode="S" schedulerid="15" kpid="26196" status="suspended" spid="306" sbid="0" ecid="0" priority="0" trancount="1" lastbatchstarted="2022-04-06T09:46:18.783" lastbatchcompleted="2022-04-06T09:46:18.783" lastattention="1900-01-01T00:00:00.783" clientapp=".Net SqlClient Data Provider" hostname="myhost" hostpid="1500" loginname="myuser" isolationlevel="read committed (2)" xactid="394724294049" currentdb="32" lockTimeout="4294967295" clientoption1="673185824" clientoption2="128056">
<executionStack>
<frame procname="MyDatabase.Main.GetMessages" line="154" stmtstart="11934" stmtend="12156" sqlhandle="0x03002000ebd98264d1bfae0066ae000001000000000000000000000000000000000000000000000000000000">
SELECT ID, Message FROM [dbo].[Messages] WHERE MessageType = @Type …
Run Code Online (Sandbox Code Playgroud)