MSSQL死锁图仅列出一个进程

时间:2018-08-06 15:01:35

标签: sql-server database-deadlocks

我一直在尝试解决死锁问题,并且已经通过SQL Server Profiler捕获了XML死锁图(探查器和有问题的SQL Server均为2014)。我以前必须做过这样的事情,但是这确实使我陷入了困境,因为XML死锁信息仅列出了一个进程……该进程被选为受害者。这是带有表格/列名称的XML:

<deadlock-list>
 <deadlock victim="process47b021c28">
  <process-list>
   <process id="process47b021c28" taskpriority="0" logused="0" waitresource="METADATA: database_id = 28 USER_TYPE(user_type_id = 261), lockPartitionId = 0" waittime="1267" ownerId="6009456" transactionname="@equipmentIDs" lasttranstarted="2018-08-06T10:37:58.643" XDES="0x3a53a63b0" lockMode="Sch-S" schedulerid="2" kpid="10512" status="suspended" spid="55" sbid="0" ecid="0" priority="0" trancount="1" lastbatchstarted="2018-08-06T10:37:58.607" lastbatchcompleted="2018-08-06T10:37:58.597" lastattention="1900-01-01T00:00:00.597" clientapp=".Net SqlClient Data Provider" hostname="(scrubbed)" hostpid="15300" loginname="(scrubbed)" isolationlevel="read committed (2)" xactid="5845226" currentdb="28" lockTimeout="4294967295" clientoption1="671219744" clientoption2="128056">
    <executionStack>
     <frame procname="unknown" line="68" stmtstart="-1" sqlhandle="0x03001c00063d8761a839af0034a9000000000000000000000000000000000000000000000000000000000000">
unknown     </frame>
     <frame procname="adhoc" line="5" stmtstart="436" stmtend="1352" sqlhandle="0x02000000466dca27e95c8209c65527d104fd85037ea1b3520000000000000000000000000000000000000000">
unknown     </frame>
    </executionStack>
    <inputbuf>
declare @internalGuid uniqueidentifier = N&apos;00000001-0000-0000-0000-000000000000&apos;;
declare @now datetime2 = getdate();

insert into
    MyTable (
        [id],
        [cbr],
        [created],
        [mbr],
        [modified],
        [value1],
        [value2],
        [latitude],
        [longitude],
        [value3],
        [indicator]
    )
select
    [id],
    @internalGuid,
    @now,
    @internalGuid,
    @now,
    [value1],
    [value2],
    [latitude],
    [longitude],
    [value3],
    1
from
    MyOtherTable;    </inputbuf>
   </process>
  </process-list>
  <resource-list>
   <metadatalock subresource="USER_TYPE" classid="user_type_id = 261" dbid="28" lockPartition="0" id="lock3a4c33a80" mode="Sch-M">
    <owner-list>
     <owner id="process47b021c28" mode="Sch-M"/>
     <owner id="process47b021c28" mode="Sch-S" requestType="wait"/>
    </owner-list>
    <waiter-list>
     <waiter id="process47b021c28" mode="Sch-S" requestType="wait"/>
    </waiter-list>
   </metadatalock>
  </resource-list>
 </deadlock>
</deadlock-list>

user_type_id 261对应于我的一种用户定义类型,该锁似乎在该类型本身上,除非我误解了这种锁(完全可能)。如果真是这样,我认为这与死锁数据中仅显示一个进程有关。请注意,死锁数据中显示的查询是对具有插入触发器的表的插入...,并且该触发器使用用户定义的类型。

编辑(2018-08-06):这是触发代码的紧急清理版本:

create trigger [dbo].[TR_MyTable_UpdateDerefTable]
on [dbo].[MyTable]
after insert, update, delete
as
begin
    set nocount on

    declare @myIDs ObjectIDType; -- ObjectIDType is a user-define table type

    insert into @myIDs
        select i.guidItemId
        from inserted i inner join DerefTable ri on i.value1 = ri.guidItemId

        union

        select d.guidItemId
        from deleted d inner join DerefTable ri on d.value = ri.guidItemId;

    declare
        @dataTypeTL int = 1,
        @dataTypeCML int = 2,
        @dataTypeDL int = 5;

    -- Update dereferenced information, if applicable
    if exists(select top 1 1 from @myIDs)
    begin
        update ri set
            [DerefValue] = eq_loc.value2,
            [DerefValueSource] = case
                                    when eq_loc.IsFromSourceTL = 1 then @dataTypeTL
                                    when eq_loc.IsFromSourceCML = 1 then @dataTypeCML
                                    when eq_loc.IsFromSourceDL = 1 then @dataTypeDL
                                    else NULL
                                 end,
            [DerefValueDescription] = lri.itemName,
            [DerefValueType] = lri.itemType,
            [DerefValueCategory] = lri.itemTypeCategory,
            [DerefValueBU] = lri.buId
        from
            @myIDs e
        left join MyTable eq_loc
        on eq_loc.id = (
            select top 1 l.id
            from MyTable as l
            where l.value1 = e.guidItemId
            order by l.[Timestamp] desc 
        )
        left join DerefTable ri on e.guidItemId = ri.DisplayguidId
        left join DerefTable lri on eq_loc.value2 = lri.guidItemId
    end

    set nocount off
end;

编辑(2018-08-06):为了使这个问题更清楚,因为周围存在太多的背景信息,这对我来说很难发布,这就是我希望对以下内容有更好的理解:死锁图XML仅列出单个进程的某些情况下的示例?除了删除用户定义的类型外,哪些操作会声明对用户定义的类型的锁定?就我而言,假设这是用户定义的表类型,那么XML信息是否可能误导我以为类型对象本身已被锁定,而实际上该表类型的 instance 具有锁定? (在那最后一种情况下,我认为列出的单个进程本身会死锁)

编辑(2018-08-07):我缩小了锁的另一端,它与用户定义类型本身的删除和创建有关。符号似乎指向表类型定义本身上的锁,而不是该类型实例中的数据上的锁。如果您还记得的话,这是在架构升级路径的上下文中。在某一时刻,将删除此用户定义的表类型(ID为261,如死锁图中所示),并使用附加的列和索引重新创建。从那里开始,在命中触发死锁的语句(被选为受害者)之前,还要处理数十个其他语句(组成许多批次),跨越两个后续版本步骤。中间的语句花了足够的时间,如果这是一个时间问题,我会感到惊讶,但这是我的理解开始下降的地方。我不知道在MSSQL中锁定用户定义类型会发生什么,可以这么说。我当然可以理解为什么受害者进程中的语句依赖于该用户定义类型的重新定义...但是我还不了解的是,可能会导致死锁情况的其他依赖关系会增加。如果我准备好重现场景,以便事先手动更新用户定义的类型,然后在升级过程中为其注释掉drop / create语句,则整个过程将按预期运行并成功完成。

0 个答案:

没有答案