我已经使用deadlock graph in SQL Server 2008诊断了我的server中的死锁问题。
这个问题与我的索引有关。我有两个查询:一个包含大量联接和子查询的长时间运行报告,根据基表上的两个不同日期提取数据;另一个快速更新查询,用于更新该基表上的相同日期。我有两个索引,报表希望在这两个索引上都有一个共享密钥锁,而update查询希望对这两个索引都设置一个独占密钥锁,而且每个查询都只能获得其中一个键,因此两者都不能继续。
我能做些什么来解决这个问题?
以下是我处境的所有细节:
我的基本表如下所示:
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查询需要对两个索引进行独占锁定,以便更新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 = 'C', @upDate = '8/3/2012 5:37:20 AM', @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>
发布于 2012-08-03 10:18:30
基于注释中的Q/A讨论,在分析死锁图之后,这是报告查询没有被这两个索引完全覆盖的情况。报告将首先开始查看非聚集索引。它没有找到所有需要的信息。因此,它在主表上执行键查找,以获取剩余的数据。但是更新的工作方式正好相反。更新将首先锁定主表,并更新其数据,然后查找所有索引并更新它们。因此陷入僵局。
解决这一问题的一种方法是按索引覆盖整个报表查询。但这意味着更新将变得缓慢。
其他解决方案是将报表查询分解为两个,并使用临时表变量从索引中收集数据,然后进行键查找。注报告查询不应在可序列化事务模式下运行。否则,事务将不会释放它刚刚读取的读锁。
希望我能说清楚。如果你有任何疑问请告诉我。
https://stackoverflow.com/questions/11800778
复制相似问题