我在桌子上遇到了奇怪的死锁(几张桌子,但它们都很相似),无论我多少尝试研究Range锁,都无法理解它。一个进程始终只有SELECT
并且正在使用RangeS-U,然后尝试将其转换为RangeS-S。为什么Select会首先选择RangeS-U?其他进程执行UPDATE
并使用RangeX-X并尝试转换为X.有时第二个进程有X并尝试获取X(或者我正在错误地读取图形)。主键索引字段永远不会更新,并且表上没有其他索引。业务流程的方式,我可以肯定,选择和更新都与具有大重叠的记录一起工作。如果需要,可以提供更多信息,表格模式和死锁图如下所示。
表 -
CREATE TABLE [dbo].[DeadlockTable] (
[ID] [bigint] NOT NULL ,
[Hour] [tinyint] NOT NULL ,
[Status] [varchar] (32) COLLATE Latin1_General_BIN NOT NULL ,
[MW] [decimal](19, 6) NULL ,
[CreationUserID] [int] NULL ,
[CreationTime] [datetime] NULL ,
[ModificationUserID] [int] NULL ,
[ModificationTime] [datetime] NULL ,
[SubmissionUserID] [int] NULL ,
[SubmissionTime] [datetime] NULL ,
[ConfigurationID] [varchar] (64) COLLATE Latin1_General_BIN NULL ,
CONSTRAINT [PK_DeadlockTable] PRIMARY KEY CLUSTERED
(
[ID],
[Hour]
) ON [PRIMARY]
) ON [PRIMARY]
GO
死锁XML -
<deadlock-list>
<deadlock victim="process5e13b88">
<process-list>
<process id="process5e13b88" taskpriority="0" logused="0" waitresource="KEY: 22:72057594344112128 (6123af010c07)" waittime="2978" ownerId="265837907" transactionname="INSERT" lasttranstarted="2017-09-01T10:04:10.767" XDES="0x16fb323b0" lockMode="RangeS-S" schedulerid="2" kpid="5316" status="suspended" spid="83" sbid="0" ecid="0" priority="0" trancount="2" lastbatchstarted="2017-09-01T10:04:10.430" lastbatchcompleted="2017-09-01T10:04:09.907" clientapp="..." hostname="..." hostpid="7980" loginname="..." isolationlevel="serializable (4)" xactid="265837907" currentdb="22" lockTimeout="4294967295" clientoption1="673185824" clientoption2="128056">
<executionStack>
<frame procname="adhoc" line="40" stmtstart="3776" stmtend="7404" sqlhandle="0x020000009555563118dcb9a28a078c9faa795d95341a9119">
INSERT INTO #TempTable (
...
)
SELECT DISTINCT
...
FROM Table1 B
LEFT JOIN DeadlockTable P ON B.[ID] = {more joins, got cropped}
</frame>
<frame procname="mssqlsystemresource.sys.sp_executesql" line="1" sqlhandle="0x0400ff7fbe80662601000000000000000000000000000000">
sp_executesql
</frame>
<frame procname="EXEC SPROC" line="386" stmtstart="28814" stmtend="29462" sqlhandle="0x03001600afff210aad8d3f01d0a700000100000000000000">
EXEC sp_executesql ...
</frame>
<frame procname="adhoc" line="1" sqlhandle="0x010016009a0b8926e0fb577e010000000000000000000000">
EXEC SPROC ...
</frame>
</executionStack>
<inputbuf>
EXEC SPROC ...
</inputbuf>
</process>
<process id="process5e45b88" taskpriority="0" logused="236" waitresource="KEY: 22:72057594344112128 (55ed2fdeaf5a)" waittime="3130" ownerId="265839001" transactionname="UPDATE" lasttranstarted="2017-09-01T10:04:14.840" XDES="0x484c171b0" lockMode="X" schedulerid="7" kpid="4852" status="suspended" spid="90" sbid="0" ecid="0" priority="0" trancount="2" lastbatchstarted="2017-09-01T10:04:14.817" lastbatchcompleted="2017-09-01T10:04:11.883" clientapp="..." hostname="..." hostpid="7980" loginname="..." isolationlevel="read committed (2)" xactid="265839001" currentdb="22" lockTimeout="4294967295" clientoption1="673185824" clientoption2="128056">
<executionStack>
<frame procname="EXEC SPROC2" line="141" stmtstart="9324" stmtend="10424" sqlhandle="0x03001600a8150d4e1c673f01d0a700000100000000000000">
UPDATE BP
SET BP.[Status] = CASE @Cancel WHEN 1 THEN 'Voided' ELSE 'Submitted' END, BP.[MW] = CASE @Cancel WHEN 1 THEN 0 ELSE BP.[MW] END, BP.[SubmissionUserID] = @SubmissionUserID, BP.[SubmissionTime] = @SubmissionTime
FROM #FinalResult FR
CROSS JOIN Hour25 H25
INNER JOIN DeadLockTable BP ON BP.[ID] = FR.[ID] AND BP.[Hour] = H25.[HE]
INNER JOIN fnc_List2Table(@HourList, ',') HL ON H25.[HE] = HL.[Value] OR @HourList = '0'
WHERE (FR.[MarketType] = 1 OR (FR.[MarketType] = 2 AND BP.[Hour] = FR.[Hour]))
</frame>
<frame procname="adhoc" line="2" stmtstart="18" sqlhandle="0x010016002c9cbb0aa05380f3000000000000000000000000">
EXEC SPROC2
</frame>
</executionStack>
<inputbuf>
EXEC SPROC2
</inputbuf>
</process>
</process-list>
<resource-list>
<keylock hobtid="72057594344112128" dbid="22" objectname="DealockTable" indexname="PK_DealockTable" id="lock451ea9e80" mode="X" associatedObjectId="72057594344112128">
<owner-list>
<owner id="process5e45b88" mode="X"/>
</owner-list>
<waiter-list>
<waiter id="process5e13b88" mode="RangeS-S" requestType="wait"/>
</waiter-list>
</keylock>
<keylock hobtid="72057594344112128" dbid="22" objectname="DealockTable" indexname="PK_DealockTable" id="lock109ed6380" mode="RangeS-U" associatedObjectId="72057594344112128">
<owner-list>
<owner id="process5e13b88" mode="RangeS-S"/>
</owner-list>
<waiter-list>
<waiter id="process5e45b88" mode="X" requestType="convert"/>
</waiter-list>
</keylock>
</resource-list>
</deadlock>
</deadlock-list>
答案 0 :(得分:2)
当一个进程(受害者)在serializable
级别上读取而另一个进程更新同一个集群表时,这是一个典型的死锁。
你对转换成什么感到困惑。
第一个进程(&#34; process5e13b88&#34;)已获得RangeS-S
锁定并等待另一个RangS-S
锁定(其中X
锁定更新进程),它没有变换。
第二个&#34; process5e45b88&#34;已经锁定了一个密钥X
和另一个密钥U
,并希望将其转换为X
,但它不能,因为RangeS-S
锁定。
我附上图片,你可以看到一个进程想要并且只获取RangeS-S
个锁和另一个X
个锁。
当您看到RangeS-U
锁定时,这表示该范围有RangeS-S
锁,但该密钥本身已U
锁定
答案 1 :(得分:0)
尝试使用连接列作为键列并将返回的(即SELECT部分中的列)列作为包含列,在死锁表上创建非聚簇索引。
阅读Using a Clustered Index to Solve a SQL Server Deadlock Issue以获取进一步说明。我知道标题听起来并不像我告诉你的那样,但文章展示了如何使用非聚集索引来解决死锁问题。