由于keylock涉及3个进程的死锁

时间:2017-08-04 23:09:53

标签: sql sql-server concurrency ssms deadlock

我试图确定这种死锁是如何发生的,以及我需要采取哪些措施来防止它再次发生。

我从SSMS附加死锁图形图像,SSMS图像提供的分辨率不好,我道歉。 enter image description here

这里发生的是3个进程被锁定在一个循环中,所有等待锁定主键以释放表SecurityObject

此表的主键是群集的,是一个复合键,包含四列

每个进程正在运行的语句如下所示。它是一个删除命令,删除表中匹配单个列的所有记录。该列是GUID标识符,它是复合群集主键中的四列之一。

DELETE FROM SecurityObject WHERE col1 = @val1

其中col1是主键中的四列之一。

我很难理解这种情况是如何发生的?如何为主键锁定出现死锁情况?

下面是死锁xml图:

<deadlock>
    <victim-list>
        <victimProcess id="processaeabf84108"/>
    </victim-list>
    <process-list>
        <process id="processaeabf84108" taskpriority="0" logused="0" waitresource="KEY: 14:72057594041925632 (00f78314b62e)" waittime="1754" ownerId="6629325" transactionname="user_transaction" lasttranstarted="2017-08-04T15:16:55.747" XDES="0xaea526f498" lockMode="X" schedulerid="2" kpid="16620" status="suspended" spid="73" sbid="0" ecid="0" priority="0" trancount="2" lastbatchstarted="2017-08-04T15:16:55.747" lastbatchcompleted="2017-08-04T15:16:55.747" lastattention="1900-01-01T00:00:00.747" clientapp=".Net SqlClient Data Provider" hostname="RDXP0165C9JAWIE" hostpid="19084" loginname="REDMOND\RDXP0165C9JAWIE$" isolationlevel="read committed (2)" xactid="6629325" currentdb="14" lockTimeout="4294967295" clientoption1="671088672" clientoption2="128056">
            <executionStack>
                <frame procname="SecurityAuthorization.DB.dbo.spDeleteAllSecurityObjects" line="5" stmtstart="342" stmtend="474" sqlhandle="0x03000e00b56a9938f8fcba00c3a7000001000000000000000000000000000000000000000000000000000000">  DELETE FROM [SecurityObject] WHERE [EnvironmentId] = @EnvironmentI    </frame>
            </executionStack>
            <inputbuf>  Proc [Database Id = 14 Object Id = 949578421]   </inputbuf>
        </process>
        <process id="processaea64a9468" taskpriority="0" logused="0" waitresource="KEY: 14:72057594041925632 (e0caa7da41f0)" waittime="3981" ownerId="6629329" transactionname="user_transaction" lasttranstarted="2017-08-04T15:16:55.750" XDES="0xaea9602408" lockMode="X" schedulerid="1" kpid="14152" status="suspended" spid="76" sbid="0" ecid="0" priority="0" trancount="2" lastbatchstarted="2017-08-04T15:16:55.750" lastbatchcompleted="2017-08-04T15:16:55.750" lastattention="1900-01-01T00:00:00.750" clientapp=".Net SqlClient Data Provider" hostname="RDXP0165C9JAWIE" hostpid="19084" loginname="REDMOND\RDXP0165C9JAWIE$" isolationlevel="read committed (2)" xactid="6629329" currentdb="14" lockTimeout="4294967295" clientoption1="671088672" clientoption2="128056">
            <executionStack>
                <frame procname="SecurityAuthorization.DB.dbo.spDeleteAllSecurityObjects" line="5" stmtstart="342" stmtend="474" sqlhandle="0x03000e00b56a9938f8fcba00c3a7000001000000000000000000000000000000000000000000000000000000">  DELETE FROM [SecurityObject] WHERE [EnvironmentId] = @EnvironmentI    </frame>
            </executionStack>
            <inputbuf>  Proc [Database Id = 14 Object Id = 949578421]   </inputbuf>
        </process>
        <process id="processaea686fc28" taskpriority="0" logused="884" waitresource="KEY: 14:72057594041925632 (e0caa7da41f0)" waittime="2105" ownerId="6638253" transactionname="user_transaction" lasttranstarted="2017-08-04T15:16:57.627" XDES="0xaea9460e58" lockMode="X" schedulerid="2" kpid="6528" status="suspended" spid="79" sbid="0" ecid="0" priority="0" trancount="2" lastbatchstarted="2017-08-04T15:16:57.627" lastbatchcompleted="2017-08-04T15:16:57.627" lastattention="1900-01-01T00:00:00.627" clientapp=".Net SqlClient Data Provider" hostname="RDXP0165C9JAWIE" hostpid="19084" loginname="REDMOND\RDXP0165C9JAWIE$" isolationlevel="read committed (2)" xactid="6638253" currentdb="14" lockTimeout="4294967295" clientoption1="671088672" clientoption2="128056">
            <executionStack>
                <frame procname="SecurityAuthorization.DB.dbo.spDeleteAllSecurityObjects" line="5" stmtstart="342" stmtend="474" sqlhandle="0x03000e00b56a9938f8fcba00c3a7000001000000000000000000000000000000000000000000000000000000">  DELETE FROM [SecurityObject] WHERE [EnvironmentId] = @EnvironmentI    </frame>
            </executionStack>
            <inputbuf>  Proc [Database Id = 14 Object Id = 949578421]   </inputbuf>
        </process>
    </process-list>
    <resource-list>
        <keylock hobtid="72057594041925632" dbid="14" objectname="SecurityAuthorization.DB.dbo.SecurityObject" indexname="PK__Security__185B78FE57F79F91" id="lockaead1a0680" mode="X" associatedObjectId="72057594041925632">
            <owner-list>
                <owner id="processaea686fc28" mode="X"/>
            </owner-list>
            <waiter-list>
                <waiter id="processaeabf84108" mode="X" requestType="wait"/>
            </waiter-list>
        </keylock>
        <keylock hobtid="72057594041925632" dbid="14" objectname="SecurityAuthorization.DB.dbo.SecurityObject" indexname="PK__Security__185B78FE57F79F91" id="lockae6d468f80" mode="X" associatedObjectId="72057594041925632">
            <owner-list>
                <owner id="processaeabf84108" mode="X"/>
            </owner-list>
            <waiter-list>
                <waiter id="processaea64a9468" mode="X" requestType="wait"/>
            </waiter-list>
        </keylock>
        <keylock hobtid="72057594041925632" dbid="14" objectname="SecurityAuthorization.DB.dbo.SecurityObject" indexname="PK__Security__185B78FE57F79F91" id="lockae6d468f80" mode="X" associatedObjectId="72057594041925632">
            <owner-list>
                <owner id="processaea64a9468" mode="X" requestType="wait"/>
            </owner-list>
            <waiter-list>
                <waiter id="processaea686fc28" mode="X" requestType="wait"/>
            </waiter-list>
        </keylock>
    </resource-list>
</deadlock>  

这是存储过程的执行计划:

enter image description here

2 个答案:

答案 0 :(得分:2)

[1]了解死锁的最佳方法是分析XML格式的死锁图(* .xdl): enter image description here

[2]所有三个连接在PK_Security .... X SecurityObject`上都有一个或多个e index created on个集群锁,他们也试图获得另一个X锁。不清楚这些锁(密钥,RID,页面*等)的粒度级别是什么。此外,三个连接中的两个已使用日志0,即使它们已成功授予X锁(您是否使用可序列化隔离级别?)。

[3]此外,OP提到了

DELETE FROM SecurityObject WHERE col1 = @val1

是似乎导致这些问题的陈述。在这种情况下,此语句的执行计划也可以帮助调试此死锁。

[4]最可能的原因可能是

  • 缺少col1上的索引

  • 非默认隔离级别(例如Serializable)。

添加[1]和[3]所需的信息有助于更好地了解会发生什么。

[5] 编辑#1:我会创建以下索引

CREATE INDEX IX_SecurityObject_EnvironmentId
ON [dbo].[SecurityObject] ([EnvironmentId])

[6] 编辑#2:

-- SecurityAuthorization.DB.dbo.spDeleteAllSecurityObjects
USE DB
GO
SELECT  ps.database_id, ps.type_desc, qp.query_plan
FROM    sys.dm_exec_procedure_stats ps
OUTER APPLY sys.dm_exec_query_plan(ps.plan_handle) qp
WHERE   ps.object_id = OBJECT_ID('dbo.spDeleteAllSecurityObjects') 

答案 1 :(得分:1)

经过进一步测试,我设法将死锁场景的根本原因分离为同时调用DeleteAll(删除表中的记录子集)和Insert(插入符合DeleteAll标准的记录)

导致死锁情况的确切事件序列仍不清楚,但问题通过将隔离级别设置为serializable 来解决。

这是一个可以接受的副作用,它会损害性能(对于我的场景,我们不关心这个操作性能,因为这些操作没有被等待,这是一个火上浇油的过程)。

相关问题