3

我已經使用deadlock graph in SQL Server 2008在我的sql服務器中診斷出一個死鎖問題。如何解決索引/密鑰相關的死鎖

這個問題與我的索引有關。我有兩個查詢:一個長時間運行的報告,其中包含大量根據基表上兩個不同日期提取數據的連接和子查詢,以及一個快速更新查詢,用於更新該基表上的相同日期。我有兩個索引,報告希望在它們兩個上都有一個共享的KEY鎖,而更新查詢需要在它們兩個上都有一個獨佔的KEY鎖,並且不知何故每個查詢只設法獲得其中一個鍵,因此兩者都不能繼續。

我能做些什麼來解決這個問題?

這裏有一個關於我的情況的所有細節:

我的基本表看起來像這樣:

CREATE TABLE job_tb{ 
    job_id int IDENTITY(1,1), 
    createDate datetime NULL, 
    upDate datetime NULL, 
    dataField1 nchar(1), 
    dataField2 nchar(2), 
    --etc... 
} 

我的指標是這樣的:

CREATE NONCLUSTERED INDEX idx_createDate ON job_tb(
    createDate DESC 
) 
INCLUDE(dataField1, dataField2) 

CREATE NONCLUSTERED INDEX idx_upDate ON job_tb(
    upDate DESC 
) 
INCLUDE(dataField1, dataField2) 

最後,我更新看起來像這樣:

BEGIN TRANSACTION; 
    UPDATE job_tb 
    SET 
     dataField1 = @data 
     upDate = @upDate 
    WHERE 
     job_id = @job_id 
COMMIT TRANSACTION; 

並且報告按日期統計各種統計數據,所以我不會在這裏包括這些數據。我故意將idx_createDate和idx_upDate設計爲「覆蓋」或包含dataField1,因爲它在該報告中大量使用。

我相信報告會抓住其中一個索引的共享鎖,然後命中子查詢並請求鎖定第二個索引。同時,更新查詢需要對兩個索引進行排他鎖定,以更新upDate和包含的dataField1。

你們認爲什麼?

編輯: 這裏的XML死鎖圖形,如要求:

<deadlock-list> <deadlock> 
<victim-list> 
    <victimProcess id="processcf65288"/> 
</victim-list> 
<process-list> 
    <process id="processcf65288" taskpriority="0" logused="0" waitresource="KEY: 6:72057597970874368 (eee1799e706c)" waittime="122" ownerId="421742704" transactionname="SELECT" lasttranstarted="2012-08-03T05:37:21.257" XDES="0x8611e8800" lockMode="S" schedulerid="50" kpid="8560" status="suspended" spid="70" sbid="0" ecid="0" priority="0" trancount="0" lastbatchstarted="2012-08-03T05:37:21.257" lastbatchcompleted="2012-08-03T05:37:21.257" clientapp="Internet Information Services" hostname="xxx" hostpid="11964" loginname="xxx" isolationlevel="read committed (2)" xactid="421742704" currentdb="6" lockTimeout="4294967295" clientoption1="671088672" clientoption2="128056"> 
     <executionStack> 
      <frame procname="" line="28" stmtstart="1276" stmtend="4826" sqlhandle="0x03000600311ac36c65a31701a1a000000100000000000000"> 
      </frame> 
      <frame procname="" line="1" sqlhandle="0x01000600f61bee3600932ae3090000000000000000000000"> 
      </frame> 
     </executionStack> 
     <inputbuf> exec MonthlyReport @id = 41 
     </inputbuf> 
    </process> 
    <process id="processd2b6bc8" taskpriority="0" logused="1908" waitresource="KEY: 6:72057597970939904 (8e8117a49479)" waittime="2242" ownerId="421742551" transactionname="user_transaction" lasttranstarted="2012-08-03T05:37:20.447" XDES="0x7e84ad0a0" lockMode="X" schedulerid="63" kpid="12700" status="suspended" spid="89" sbid="0" ecid="0" priority="0" trancount="2" lastbatchstarted="2012-08-03T05:37:20.443" lastbatchcompleted="2012-08-03T05:37:20.443" clientapp="Internet Information Services" hostname="xxx" hostpid="11964" loginname="xxx" isolationlevel="read committed (2)" xactid="421742551" currentdb="6" lockTimeout="4294967295" clientoption1="673185824" clientoption2="128056"> 
     <executionStack> 
      <frame procname="" line="47" stmtstart="2342" stmtend="2640" sqlhandle="0x03000600e7dd9c717cbbb900ec9f00000100000000000000"> 
      </frame> 
      <frame procname="" line="1" sqlhandle="0x01000600311d7a152032f9be040000000000000000000000"> 
      </frame> 
     </executionStack> 
     <inputbuf> exec UpdateJob @dataField1 = &apos;C&apos;, @upDate = &apos;8/3/2012 5:37:20 AM&apos;, @job_id = 1542687 
     </inputbuf> 
    </process> 
</process-list> 
<resource-list> 
    <keylock hobtid="72057597970874368" dbid="6" objectname="" indexname="" id="lock612859900" mode="X" associatedObjectId="72057597970874368"> 
     <owner-list> 
      <owner id="processd2b6bc8" mode="X"/> 
     </owner-list> 
     <waiter-list> 
      <waiter id="processcf65288" mode="S" requestType="wait"/> 
     </waiter-list> 
    </keylock> 
    <keylock hobtid="72057597970939904" dbid="6" objectname="" indexname="" id="lock612a15300" mode="S" associatedObjectId="72057597970939904"> 
     <owner-list> 
      <owner id="processcf65288" mode="S"/> 
     </owner-list> 
     <waiter-list> 
      <waiter id="processd2b6bc8" mode="X" requestType="wait"/> 
     </waiter-list> 
    </keylock> 
</resource-list> 
</deadlock> /deadlock-list> 
+0

您的報表查詢是否包含'begin transaction'下的多個選擇? – Ankush 2012-08-03 17:53:49

+0

也可以分享死鎖圖形XML文件? – Ankush 2012-08-03 17:55:33

+0

nope報告不包含'begin transaction' – Slider345 2012-08-03 17:57:55

回答

5

基於Q /評論和分析死鎖圖形後的討論,這是情況的報告查詢ISN目前的兩項指標並未完全覆蓋。報告將首先查看非聚集索引。它沒有找到所有需要的信息。因此它在主表上進行了一次關鍵查找以獲取剩餘數據。 但更新的工作方式完全相反。更新將首先鎖定主表並更新其數據,然後查找所有索引並更新它們。因此,僵局。

解決此問題的一種方法是通過索引涵蓋整個報表查詢。但是這意味着更新會變得緩慢。

其他解決方案是將報表查詢分解爲兩部分,並使用臨時表變量從索引收集數據,然後執行鍵查找。注意報表查詢不應在可序列化的事務模式下運行。否則,事務將不會釋放它剛剛讀取的讀鎖。

希望我很清楚。如果您有任何疑問,請告訴我。

+0

好吧,我在這種情況下將這些字段添加到索引。將再次檢查死鎖圖表,以確保此死鎖消失。 – Slider345 2012-08-03 18:45:21

+0

確保在報表查詢的查詢計劃中不包含任何keylook直到主表。 – Ankush 2012-08-03 18:46:36

+0

還有一件事,如果你仍然死鎖,看看你是否可以得到資源鍵盤鎖的索引。在最後一張圖中,它是空的。在最壞的情況下,更新可以按照與報表查詢讀取方式不同的順序更新這些索引。 – Ankush 2012-08-03 19:04:08