2017-09-01 57 views
0

我在桌子上发现了奇怪的死锁(很少有表格,但它们都是相似的),无论我尝试学习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 &apos;Voided&apos; ELSE &apos;Submitted&apos; 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, &apos;,&apos;) HL ON H25.[HE] = HL.[Value] OR @HourList = &apos;0&apos; 
         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> 

死锁图形 deadlock graph from sql trace

+0

你是否需要在'serializable'事务隔离中运行select查询?这可能有助于为什么你的选择查询试图获得更高级别的锁 – Xedni

+0

@Xedni这是一个金融应用程序,所以序列化对我们来说是非常不可避免的。我也会把帖子交给dba.stackexchange,谢谢你的建议。 – Sarwara

+0

只是需要考虑的一点,因为这将有助于锁定并绊倒你的选项。你可以考虑在两个进程中使用'sp_getapplock'(它的行为更像是一个类似C#的'lock')。这样至少可以防止你添加的任何程序试图锁定你放在applock的body中的相同的东西。像快照隔离之类的东西可能也有助于研究。 – Xedni

回答

2

它的经典死锁当一个进程(受害者)读取serializable级别,另一个更新相同的聚簇表。

你对什么转化为什么感到困惑。

第一处理(“process5e13b88”)已经获得RangeS-S锁和用于另一RangS-S锁等待(这里有更新过程的X锁),将其转换没有。

第二个“process5e45b88”上获取一个键,UX锁的另一个关键,并希望将其转换为X但不能因为有RangeS-S锁。

我附上图片,您可以看到一个进程只需要获取RangeS-S个锁,另一个只能获得X个锁。

当你看到RangeS-U锁定,这意味着有RangeS-S锁定的范围,但密钥本身具有U

enter image description here

+0

你能提出一个解决方案吗?我不想做脏读,我不能可靠地重现问题,以测试任何可能改善情况的锁定提示。 – Sarwara