我在桌子上发现了奇怪的死锁(很少有表格,但它们都是相似的),无论我尝试学习Range锁定多少都无法理解它。一个进程总是只有SELECT
,并且正在使用RangeS-U,然后尝试将其转换为RangeS-S。为什么选择将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>
你是否需要在'serializable'事务隔离中运行select查询?这可能有助于为什么你的选择查询试图获得更高级别的锁 – Xedni
@Xedni这是一个金融应用程序,所以序列化对我们来说是非常不可避免的。我也会把帖子交给dba.stackexchange,谢谢你的建议。 – Sarwara
只是需要考虑的一点,因为这将有助于锁定并绊倒你的选项。你可以考虑在两个进程中使用'sp_getapplock'(它的行为更像是一个类似C#的'lock')。这样至少可以防止你添加的任何程序试图锁定你放在applock的body中的相同的东西。像快照隔离之类的东西可能也有助于研究。 – Xedni