Ste*_*eve 3 sql-server deadlock locking
死锁图:
<deadlock>
<victim-list>
<victimProcess id="process21881f1bc28" />
</victim-list>
<process-list>
<process id="process21881f1bc28" taskpriority="0" logused="0" waitresource="KEY: 7:72057594049003520 (44e4a8141ab4)" waittime="375" ownerId="313642186" transactionname="user_transaction" lasttranstarted="2018-12-09T10:00:39.007" XDES="0x217706d6408" lockMode="RangeS-U" schedulerid="2" kpid="6776" status="suspended" spid="59" sbid="0" ecid="0" priority="0" trancount="2" lastbatchstarted="2018-12-09T10:00:39.013" lastbatchcompleted="2018-12-09T10:00:39.007" lastattention="1900-01-01T00:00:00.007" clientapp=".Net SqlClient Data Provider" hostname="x" hostpid="4724" loginname="x" isolationlevel="read uncommitted (1)" xactid="313642186" currentdb="7" lockTimeout="4294967295" clientoption1="671088672" clientoption2="128056">
<executionStack>
<frame procname="adhoc" line="1" stmtstart="44308" stmtend="72024" sqlhandle="0x02000000fb261007e17c6dabc0917779a6823e14abd04fef0000000000000000000000000000000000000000">
unknown </frame>
<frame procname="unknown" line="1" sqlhandle="0x0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000">
unknown </frame>
</executionStack>
<inputbuf>
(@param0 int,@param1 int,@param2 int,@param3 real,@param4 int,@param5 int,@param6 int,@param7 nvarchar(21),@param8 int,@param9 nvarchar(7),@param10 datetime,@param11 datetime,@param12 nvarchar(14),@param13 int,@param14 int,@param15 int,@param16 real,@param17 int,@param18 int,@param19 int,@param20 nvarchar(21),@param21 int,@param22 nvarchar(7),@param23 datetime,@param24 datetime,@param25 nvarchar(14),@param26 int,@param27 int,@param28 int,@param29 real,@param30 int,@param31 int,@param32 int,@param33 nvarchar(21),@param34 int,@param35 nvarchar(12),@param36 datetime,@param37 datetime,@param38 nvarchar(14),@param39 int,@param40 int,@param41 int,@param42 real,@param43 int,@param44 int,@param45 int,@param46 nvarchar(21),@param47 int,@param48 nvarchar(12),@param49 datetime,@param50 datetime,@param51 nvarchar(14),@param52 int,@param53 int,@param54 int,@param55 real,@param56 int,@param57 int,@param58 int,@param59 nvarchar(21),@param60 int,@param61 nvarchar(7),@param62 datetime,@param63 datetime,@param64 nvarchar(14), /*INSERT INTO TradeBuffer_US_PC .... VALUES ...*/
</inputbuf>
</process>
<process id="process2187b184108" taskpriority="0" logused="4655716" waitresource="KEY: 7:72057594049003520 (233cbd3694c1)" waittime="82" ownerId="313639357" transactionname="DELETE" lasttranstarted="2018-12-09T10:00:27.050" XDES="0x2188843d8a8" lockMode="X" schedulerid="1" kpid="6340" status="suspended" spid="61" sbid="0" ecid="0" priority="0" trancount="2" lastbatchstarted="2018-12-09T10:00:00.250" lastbatchcompleted="2018-12-09T10:00:00.250" lastattention="1900-01-01T00:00:00.250" clientapp="SQLAgent - TSQL JobStep (Job 0x19A4A8C8E6580E42BAB84B11DDD66C97 : Step 1)" hostname="HWC-HWP-1098250" hostpid="4044" loginname="NT SERVICE\SQLSERVERAGENT" isolationlevel="read committed (2)" xactid="313639357" currentdb="7" lockTimeout="4294967295" clientoption1="671088672" clientoption2="128056">
<executionStack>
<frame procname="adhoc" line="27" stmtstart="7180" stmtend="7278" sqlhandle="0x0200000013d8441152a66453df9df52295e0815f8e2c4a0b0000000000000000000000000000000000000000">
unknown </frame>
</executionStack>
<inputbuf>
SET QUOTED_IDENTIFIER ON
DECLARE @LastID INT
SELECT TOP 1 @LastID = ID FROM [TradeBuffer_US_PC] ORDER BY ID DESC
IF @LastID IS NOT NULL
BEGIN
BEGIN TRY
...
DELETE FROM TradeBuffer_US_PC WHERE ID < @LastID
</inputbuf>
</process>
</process-list>
<resource-list>
<keylock hobtid="72057594049003520" dbid="7" objectname="TradeBuffer_US_PC" indexname="UX_TradeBuffer_US_PC_PlayerID_ItemID_Amount_TotalPrice_ExpireTime_GuildName" id="lock217fdb50980" mode="X" associatedObjectId="72057594049003520">
<owner-list>
<owner id="process2187b184108" mode="X" />
</owner-list>
<waiter-list>
<waiter id="process21881f1bc28" mode="RangeS-U" requestType="wait" />
</waiter-list>
</keylock>
<keylock hobtid="72057594049003520" dbid="7" objectname="TradeBuffer_US_PC" indexname="UX_TradeBuffer_US_PC_PlayerID_ItemID_Amount_TotalPrice_ExpireTime_GuildName" id="lock2178726f880" mode="RangeS-U" associatedObjectId="72057594049003520">
<owner-list>
<owner id="process21881f1bc28" mode="RangeS-U" />
</owner-list>
<waiter-list>
<waiter id="process2187b184108" mode="X" requestType="wait" />
</waiter-list>
</keylock>
</resource-list>
</deadlock>
Run Code Online (Sandbox Code Playgroud)
ID 是主要的身份密钥。
第一个进程正在执行多插入 ( INSERT INTO ... VALUES(...), (...), (...)),第二个进程正在对同一个表执行删除操作。
第二个过程是将缓冲表合并到实表并清除缓冲表。
缓冲表有一个用IGNORE_DUP_KEYon定义的唯一键。因此,多插入可能包含已在缓冲表中的重复行。
从图中似乎删除进程是排他锁的所有者,而插入进程正在等待获取更新锁以进行插入。
但是第二个 keylock 块表示插入进程拥有更新锁(我假设它是插入的新行之一)并且删除进程正在尝试获取排他锁。
这对我来说看起来很奇怪,因为删除进程已经拥有排他锁,为什么它会再次请求并失败?
删除过程在 SQL 代理作业中运行,并且未包装在begin trans块中
为什么在这种情况下会发生死锁,我可以做些什么来避免它?
插入进程 ( process21881f1bc28) 对表的非聚集索引中的键具有部分范围锁定TradeBuffer_US_PC,但正在等待范围内的其余键。
删除进程 ( process2187b184108) 对同一范围内的键之一具有排他锁,并且正在等待锁定以删除该范围内的其他键之一。
与此相关,请查看这篇非常详细的博客文章:
锁定 Microsoft SQL Server(第 20 部分)——由于 IGNORE_DUP_KEY 索引选项导致的范围锁定 (RangeS-U) 死锁
那里的作者证明了插入到具有IGNORE_DUP_KEY非聚集索引的表中会导致对SERIALIZABLE非聚集索引键的锁定行为。这是 SQL Server 提供的最严格的锁定行为,因此最不利于并发。
不幸的是,这意味着您需要做一些工作来缓解这种僵局。以下是一些可能会有所帮助的一般想法,而无需看到所涉及的代码:
您最省力的选择是以比当前更小的批次删除行。这至少会限制您遇到的死锁数量。
一个可能更大的变化是SERIALIZBLE在删除过程中显式使用隔离级别,然后对您希望在一开始删除的整个键范围执行 SELECT。这应该获取您需要删除的锁的范围。
另一种选择是利用排序。更改插入和删除过程,以便它们以相同的顺序(例如,键顺序升序)对数据进行操作。这将有望允许以相同的顺序获取锁,因此它们不太可能死锁(而只会等待不兼容的锁被释放)。
PS:我在插入过程的过程节点中注意到了这一点:
isolationlevel="read uncommitted (1)"
Run Code Online (Sandbox Code Playgroud)
我不确定您为什么要使用READ UNCOMMITTED此数据修改查询,但它可能不会按您希望的那样做。
| 归档时间: |
|
| 查看次数: |
2417 次 |
| 最近记录: |