2

在 SQL Server 2005 上,

更新同一张表中的两个不同键时,我遇到了死锁。

请注意,这两个等待资源具有相同的开始部分,但结束部分不同。

waitresource="KEY: 6:72057594090487808 (d900ed5a6cc6)" 

waitresource="KEY: 6:72057594090487808 (d900fb5261bb)"

这两个钥匙被锁住了,我需要弄清楚为什么。

question:_

如果括号中的值不同,为什么键的前半部分相同?

<deadlock-list>
 <deadlock victim="processffffffff8f5863e8">
  <process-list>
   <process id="processaf02f8" taskpriority="0" logused="0" waitresource="KEY: 6:72057594090487808 (d900fb5261bb)" waittime="2281" ownerId="1370264705" transactionname="user_transaction" lasttranstarted="2010-06-17T00:35:25.483" XDES="0x69453a70" lockMode="U" schedulerid="3" kpid="7624" status="suspended" spid="339" sbid="0" ecid="0" priority="0" transcount="2" lastbatchstarted="2010-06-17T00:35:25.483" lastbatchcompleted="2010-06-17T00:35:25.483" clientapp=".Net SqlClient Data Provider" hostname="RISKBBG_VM" hostpid="5848" loginname="RiskOpt" isolationlevel="read committed (2)" xactid="1370264705" currentdb="6" lockTimeout="4294967295" clientoption1="671088672" clientoption2="128056">
    <executionStack>
     <frame procname="MKP_RISKDB.dbo.MarketDataCurrentRtUpload" line="14" stmtstart="840" stmtend="1220" sqlhandle="0x03000600005f9d24c8878f00849d00000100000000000000">
UPDATE c WITH (ROWLOCK) SET LastUpdate = t.LastUpdate, Value = t.Value, Source = t.Source 
        FROM MarketDataCurrent c INNER JOIN #TEMPTABLE2 t ON c.MDID = t.mdid;

        -- Insert new MDID     </frame>
     <frame procname="adhoc" line="1" sqlhandle="0x010006004a58132228bf8d73000000000000000000000000">
MarketDataCurrentBlbgRtUpload     </frame>
    </executionStack>
    <inputbuf>
MarketDataCurrentBlbgRtUpload    </inputbuf>
   </process>
   <process id="processffffffff8f5863e8" taskpriority="0" logused="0" waitresource="KEY: 6:72057594090487808 (d900ed5a6cc6)" waittime="2281" ownerId="1370264646" transactionname="user_transaction" lasttranstarted="2010-06-17T00:35:25.450" XDES="0x1cb72be8" lockMode="U" schedulerid="5" kpid="1880" status="suspended" spid="287" sbid="0" ecid="0" priority="0" transcount="2" lastbatchstarted="2010-06-17T00:35:25.450" lastbatchcompleted="2010-06-17T00:35:25.450" clientapp=".Net SqlClient Data Provider" hostname="RISKAPPS_VM" hostpid="1424" loginname="RiskOpt" isolationlevel="read committed (2)" xactid="1370264646" currentdb="6" lockTimeout="4294967295" clientoption1="671088672" clientoption2="128056">
    <executionStack>
     <frame procname="MKP_RISKDB.dbo.MarketDataCurrent_BulkUpload" line="28" stmtstart="1062" stmtend="1720" sqlhandle="0x03000600a28e5e4ef4fd8e00849d00000100000000000000">
UPDATE c WITH (ROWLOCK) SET LastUpdate = getdate(), Value = t.Value, Source = @source 
FROM MarketDataCurrent c INNER JOIN #MDTUP t ON c.MDID = t.mdid
WHERE c.lastUpdate &lt; @updateTime
and   c.mdid not in (select mdid from MarketData where BloombergTicker is not null and PriceSource like &apos;Live.%&apos;)
and   c.value &lt;&gt; t.value     </frame>
     <frame procname="adhoc" line="1" stmtstart="88" sqlhandle="0x01000600c1653d0598706ca7000000000000000000000000">
exec MarketDataCurrent_BulkUpload @clearBefore, @source     </frame>
     <frame procname="unknown" line="1" sqlhandle="0x000000000000000000000000000000000000000000000000">
unknown     </frame>
    </executionStack>
    <inputbuf>
(@clearBefore datetime,@source nvarchar(10))exec MarketDataCurrent_BulkUpload @clearBefore, @source    </inputbuf>
   </process>
  </process-list>
  <resource-list>
   <keylock hobtid="72057594090487808" dbid="6" objectname="MKP_RISKDB.dbo.MarketDataCurrent" indexname="PK_MarketDataCurrent" id="lock64ac7940" mode="U" associatedObjectId="72057594090487808">
    <owner-list>
     <owner id="processffffffff8f5863e8" mode="U"/>
    </owner-list>
    <waiter-list>
     <waiter id="processaf02f8" mode="U" requestType="wait"/>
    </waiter-list>
   </keylock>
   <keylock hobtid="72057594090487808" dbid="6" objectname="MKP_RISKDB.dbo.MarketDataCurrent" indexname="PK_MarketDataCurrent" id="lockffffffffb8d2dd40" mode="U" associatedObjectId="72057594090487808">
    <owner-list>
     <owner id="processaf02f8" mode="U"/>
    </owner-list>
    <waiter-list>
     <waiter id="processffffffff8f5863e8" mode="U" requestType="wait"/>
    </waiter-list>
   </keylock>
  </resource-list>
 </deadlock>
</deadlock-list>
4

2 回答 2

2

6:72057594090487808就像database_id:hobtid在 XDL 中进一步看到的那样。

<keylock hobtid="72057594090487808" dbid="6"  
objectname="MKP_RISKDB.dbo.MarketDataCurrent" 
indexname="PK_MarketDataCurrent" id="lock64ac7940" mode="U" 
associatedObjectId="72057594090487808">

括号中的数字是其中不同键的哈希值MKP_RISKDB.dbo.MarketDataCurrent(PK_MarketDataCurrent)

于 2011-10-30T11:51:29.303 回答
2

第一部分是相同的,因为它在同一资源(可能是索引)上死锁,但等待资源的不同行(第二部分)。使用等待资源,您实际上可以获得确切的行或页面,之前的答案只识别了数据库和表或索引。将以下代码替换为 waitresource 中的相应 ID。

在你的例子中waitresource="KEY: 6:72057594090487808 (d900ed5a6cc6)

  1. 数据库- 检索与死锁有关的数据库

    SELECT * FROM sys.databases WHERE database_id IN (6)
    
  2. 表或索引——检索死锁涉及的表或索引

    SELECT b.name AS TableName, 
           c.name AS IndexName, c.type_desc AS IndexType, * 
    FROM sys.partitions a
    INNER JOIN sys.objects b 
       ON a.object_id = b.object_id
    INNER JOIN sys.indexes c 
       ON a.object_id = c.object_id  AND a.index_id = c.index_id
    WHERE partition_id IN ('72057594090487808')
    
  3. Exact Row - 检索确切的行或页面,在您的特定情况下,等待资源是一个 KEY,因此您搜索“列” %%lockres%%(是的,列名实际上是 %%lockres%%,它被称为“未记录的虚拟列” )。如果您的表不是太过时或者不是 DELETE 操作,那么您将在确定“分区 id”或“hobt_id”来自哪个表之后,从该哈希中找到确切的行,然后更改并运行下面的代码(免责声明 - 在您进行调试时,哈希值和页面位置可能已经改变,尽管密钥哈希不太可能)

    SELECT 
       sys.fn_PhysLocFormatter(%%physloc%%) AS PageResource, 
       %%lockres%% AS LockResource, *
    FROM <<InsertTableNameFromStep2Here>>
    WHERE %%lockres%% IN ('(d900ed5a6cc6)')
    

请记住,通常 2 个资源是冲突的,这会导致死锁。但是,它不一定必须是死锁图中提供的两个语句都执行两个锁定。也有可能在同一事务中(但未在死锁图中标识)的语句之前锁定了 2 个资源中的 1 个。但是死锁中的 2 个语句中的 1 个肯定涉及锁定在记录死锁时导致死锁的 2 个资源中的 1 个。

在执行上述所有操作之前,如果您有死锁图会很方便,您可以使用 Profiler 或带有跟踪标志的 SQL 日志进行跟踪,但更方便的方法是使用 SQL Server 扩展事件功能。只需运行下面的查询,您就可以检索死锁图。

SELECT
   DATEADD(mi, DATEDIFF(mi, GETUTCDATE(), CURRENT_TIMESTAMP), DeadlockEventXML.value('(event/@timestamp)[1]', 'datetime2')) AS [EventTime],
   DeadlockEventXML.value('(//process[@id[//victim-list/victimProcess[1]/@id]]/@hostname)[1]', 'nvarchar(max)') AS HostName,
   DeadlockEventXML.value('(//process[@id[//victim-list/victimProcess[1]/@id]]/@clientapp)[1]', 'nvarchar(max)') AS ClientApp,
   DB_NAME(DeadlockEventXML.value('(//process[@id[//victim-list/victimProcess[1]/@id]]/@currentdb)[1]', 'nvarchar(max)')) AS [DatabaseName],
   DeadlockEventXML.value('(//process[@id[//victim-list/victimProcess[1]/@id]]/@transactionname)[1]', 'nvarchar(max)') AS VictimTransactionName,
   DeadlockEventXML.value('(//process[@id[//victim-list/victimProcess[1]/@id]]/@isolationlevel)[1]', 'nvarchar(max)') AS IsolationLevel,
   DeadlockEventXML.query('(event/data[@name="xml_report"]/value/deadlock)[1]') AS DeadLockGraph,
   DeadlockEventXML
FROM
(
   SELECT 
      XEvent.query('.') AS DeadlockEventXML,
     Data.TargetData
   FROM 
   (
      SELECT 
        CAST(target_data AS XML) AS TargetData
        FROM sys.dm_xe_session_targets st
        JOIN sys.dm_xe_sessions s ON s.address = st.event_session_address
        WHERE s.name = 'system_health' AND
          st.target_name = 'ring_buffer'
   ) AS Data
   CROSS APPLY TargetData.nodes('RingBufferTarget/event[@name="xml_deadlock_report"]') AS XEventData(XEvent)
) AS DeadlockInfo

对于 SQL Server 2008 和 2008 R2,使用此查询。

SELECT
   DATEADD(mi, DATEDIFF(mi, GETUTCDATE(), CURRENT_TIMESTAMP), DeadlockEventXML.value('(event/@timestamp)[1]', 'datetime2')) AS [EventTime],
   DeadlockEventXML.value('(//process[@id[//victim-list/victimProcess[1]/@id]]/@hostname)[1]', 'nvarchar(max)') AS HostName,
   DeadlockEventXML.value('(//process[@id[//victim-list/victimProcess[1]/@id]]/@clientapp)[1]', 'nvarchar(max)') AS ClientApp,
   DB_NAME(DeadlockEventXML.value('(//process[@id[//victim-list/victimProcess[1]/@id]]/@currentdb)[1]', 'nvarchar(max)')) AS [DatabaseName],
   DeadlockEventXML.value('(//process[@id[//victim-list/victimProcess[1]/@id]]/@transactionname)[1]', 'nvarchar(max)') AS VictimTransactionName,
   DeadlockEventXML.value('(//process[@id[//victim-list/victimProcess[1]/@id]]/@isolationlevel)[1]', 'nvarchar(max)') AS IsolationLevel,
   DeadlockEventXML.query('(event/data[@name="xml_report"]/value/deadlock)[1]') AS DeadLockGraph,
   DeadlockEventXML
FROM
(
   SELECT 
            CONVERT(XML,REPLACE(REPLACE(CONVERT(VARCHAR(MAX),XEvent.query('.')), '&lt;', '<'), '&gt;', '>'))
   AS DeadlockEventXML,
     Data.TargetData
   FROM 
   (
      SELECT 
        CAST(target_data AS XML) AS TargetData
        FROM sys.dm_xe_session_targets st
        JOIN sys.dm_xe_sessions s ON s.address = st.event_session_address
        WHERE s.name = 'system_health' AND
          st.target_name = 'ring_buffer'
   ) AS Data
   CROSS APPLY TargetData.nodes('RingBufferTarget/event[@name="xml_deadlock_report"]') AS XEventData(XEvent)
) AS DeadlockInfo
于 2014-08-08T20:47:40.640 回答