ReadCommited IL下的死锁

时间:2012-11-09 15:02:53

标签: sql-server profiling deadlock isolation-level

为什么在RC隔离级别运行事务的进程如果已在另一个表上运行select语句,则会保持 IX 页锁定?我的意思是,我认为当语句结束时会释放锁(这就是为什么我们可以进行不可重复的读取)。

这是死锁xml:

<deadlock-list>
 <deadlock victim="process5cd048">
  <process-list>
   <process id="process5cd048" taskpriority="0" logused="10000" waittime="2220" schedulerid="3" kpid="5764" status="suspended" spid="62" sbid="0" ecid="0" priority="0" trancount="1" lastbatchstarted="2012-11-09T12:16:52.730" lastbatchcompleted="2012-11-09T12:16:52.730" lastattention="2012-11-08T17:33:28.597" clientapp=".Net SqlClient Data Provider" hostname="CWCEINAW" hostpid="4908" loginname="cwcuser" isolationlevel="read committed (2)" xactid="1157173773" currentdb="5" lockTimeout="4294967295" clientoption1="671088672" clientoption2="128056">
    <executionStack>
     <frame procname="adhoc" line="1" sqlhandle="0x020000005b3f1719cc3b4ad87e96487fe7fbf624ab5c2984">
SELECT * FROM WP_CashCenter_StockTransactionLine
                    WHERE [StockTransaction_id] IN (
                        SELECT DISTINCT [ST].[id]
                        FROM WP_CashCenter_StockTransaction AS [ST]
                            LEFT JOIN WP_CashCenter_StockTransactionLine AS [STL] ON ([STL].[StockTransaction_id] = [ST].[id])
                        WHERE [ST].[Type] IN (1, 0, 10, 9)
AND ([STL].[Direction] IN (1, 0) OR [STL].[id] IS NULL) 
AND [ST].[Status] IN (0, 1)
AND ([STL].[StockContainer_id] = 3000080311 OR [ST].[StockContainerID] = 3000080311))     </frame>
    </executionStack>
    <inputbuf>
SELECT * FROM WP_CashCenter_StockTransactionLine
                    WHERE [StockTransaction_id] IN (
                        SELECT DISTINCT [ST].[id]
                        FROM WP_CashCenter_StockTransaction AS [ST]
                            LEFT JOIN WP_CashCenter_StockTransactionLine AS [STL] ON ([STL].[StockTransaction_id] = [ST].[id])
                        WHERE [ST].[Type] IN (1, 0, 10, 9)
AND ([STL].[Direction] IN (1, 0) OR [STL].[id] IS NULL) 
AND [ST].[Status] IN (0, 1)
AND ([STL].[StockContainer_id] = 3000080311 OR [ST].[StockContainerID] = 3000080311))    </inputbuf>
   </process>
   <process id="process33ebc8" taskpriority="0" logused="10676" waitresource="PAGE: 5:1:1144344" waittime="2221" ownerId="1157173773" transactionname="user_transaction" lasttranstarted="2012-11-09T12:16:52.197" XDES="0x41518b140" lockMode="S" schedulerid="5" kpid="5272" status="suspended" spid="62" sbid="0" ecid="9" priority="0" trancount="0" lastbatchstarted="2012-11-09T12:16:52.730" lastbatchcompleted="2012-11-09T12:16:52.730" clientapp=".Net SqlClient Data Provider" hostname="CWCEINAW" hostpid="4908" isolationlevel="read committed (2)" xactid="1157173773" currentdb="5" lockTimeout="4294967295" clientoption1="671088672" clientoption2="128056">
    <executionStack>
     <frame procname="adhoc" line="1" sqlhandle="0x020000005b3f1719cc3b4ad87e96487fe7fbf624ab5c2984">
SELECT * FROM WP_CashCenter_StockTransactionLine
                    WHERE [StockTransaction_id] IN (
                        SELECT DISTINCT [ST].[id]
                        FROM WP_CashCenter_StockTransaction AS [ST]
                            LEFT JOIN WP_CashCenter_StockTransactionLine AS [STL] ON ([STL].[StockTransaction_id] = [ST].[id])
                        WHERE [ST].[Type] IN (1, 0, 10, 9)
AND ([STL].[Direction] IN (1, 0) OR [STL].[id] IS NULL) 
AND [ST].[Status] IN (0, 1)
AND ([STL].[StockContainer_id] = 3000080311 OR [ST].[StockContainerID] = 3000080311))     </frame>
    </executionStack>
    <inputbuf>
    </inputbuf>
   </process>
   <process id="process4e13048" taskpriority="0" logused="11448" waitresource="PAGE: 5:1:1144209" waittime="2172" ownerId="1157175935" transactionname="user_transaction" lasttranstarted="2012-11-09T12:16:52.997" XDES="0x3458e63b0" lockMode="S" schedulerid="7" kpid="3912" status="suspended" spid="58" sbid="0" ecid="0" priority="0" trancount="1" lastbatchstarted="2012-11-09T12:16:53.070" lastbatchcompleted="2012-11-09T12:16:53.067" clientapp=".Net SqlClient Data Provider" hostname="CWCEINAW" hostpid="4908" loginname="cwcuser" isolationlevel="read committed (2)" xactid="1157175935" currentdb="5" lockTimeout="4294967295" clientoption1="671088672" clientoption2="128056">
    <executionStack>
     <frame procname="adhoc" line="1" stmtstart="160" sqlhandle="0x02000000193c8a3bb37a516f7a7155b01a67b7772459f53e">
SELECT [D].*
                        FROM WP_Discrepancy as [D]
                        WHERE [D].[Level] = @Level
                        AND [D].[Status] IN (@StatusInProgress, @StatusConfirmed)
                        AND [D].[StockContainerID] = @StockContainerID     </frame>
     <frame procname="unknown" line="1" sqlhandle="0x000000000000000000000000000000000000000000000000">
unknown     </frame>
    </executionStack>
    <inputbuf>
(@Level int,@StatusInProgress int,@StatusConfirmed int,@StockContainerID bigint)SELECT [D].*
                        FROM WP_Discrepancy as [D]
                        WHERE [D].[Level] = @Level
                        AND [D].[Status] IN (@StatusInProgress, @StatusConfirmed)
                        AND [D].[StockContainerID] = @StockContainerID    </inputbuf>
   </process>
  </process-list>
  <resource-list>
   <exchangeEvent id="Pipe43a6da400" WaitType="e_waitPipeGetRow" nodeId="1">
    <owner-list>
     <owner id="process33ebc8"/>
    </owner-list>
    <waiter-list>
     <waiter id="process5cd048"/>
    </waiter-list>
   </exchangeEvent>
   <pagelock fileid="1" pageid="1144344" dbid="5" objectname="WebPortal.dbo.WP_CashCenter_StockTransactionLine" id="lock326ee4180" mode="IX" associatedObjectId="72057594149601280">
    <owner-list>
     <owner id="process4e13048" mode="IX"/>
    </owner-list>
    <waiter-list>
     <waiter id="process33ebc8" mode="S" requestType="wait"/>
    </waiter-list>
   </pagelock>
   <pagelock fileid="1" pageid="1144209" dbid="5" objectname="WebPortal.dbo.WP_Discrepancy" id="lock339da6b80" mode="SIX" associatedObjectId="72057594163625984">
    <owner-list>
     <owner id="process5cd048" mode="SIX"/>
    </owner-list>
    <waiter-list>
     <waiter id="process4e13048" mode="S" requestType="wait"/>
    </waiter-list>
   </pagelock>
  </resource-list>
 </deadlock>
</deadlock-list>

正如您所见,流程 process4e13048 在表WP_CashCenter_StockTransactionLine的某些页面上拥有 IX 锁。尝试执行的当前语句是SELECT,无法完成,因为它需要WP_Discrepancy页面上的共享锁定(很明显)与进程持有的 SIX 锁定冲突的 process5cd048 即可。

同样,为什么后一个过程会持有 SIX 锁?根据执行堆栈,正在执行的语句是SELECTWP_CashCenter_StockTransactionLine表。

如果我使用 Serializable IL运行事务,我希望同一进程中先前语句获取的锁保留。但事实并非如此。

任何人都能解释一下我对RC隔离级别的错误吗? 感谢。

1 个答案:

答案 0 :(得分:1)

  

我认为当语句结束时会释放锁

不写锁(X,IX,S-IX等)。写锁必须遵守two phase locking,因此它们在事务结束时被释放。想想相反的意思:DELETE在事务结束前删除行上的X锁定,稍后并发事务用相同的键INSERT一个新行(它可以,因为没有锁定),现在第一个事务需要回滚。它能做什么,它无法插回它删除的行,因为密钥是在第二个事务的同时获取的,所以它无法回滚。

因此运行SELECT时会发生死锁,因为运行这些选择的事务在运行SELECT之前已获取写锁