Warning: file_get_contents(/data/phpspider/zhask/data//catemap/5/sql/86.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Sql 将触发器的一部分提取到存储过程后的死锁_Sql_Sql Server_Tsql_Deadlock_Database Deadlocks - Fatal编程技术网

Sql 将触发器的一部分提取到存储过程后的死锁

Sql 将触发器的一部分提取到存储过程后的死锁,sql,sql-server,tsql,deadlock,database-deadlocks,Sql,Sql Server,Tsql,Deadlock,Database Deadlocks,今天我们有一个非常有趣的案例,让我很困惑。简而言之,我们做了一些重构,从重复的代码中清除触发器,将其提取到单个可重用的存储过程中。我们认为这种重构不会有副作用,但我们大错特错了。发布后,我们遇到了很多死锁和性能下降,没有明显的原因。在检查了系统表以了解数据库是由什么组成的之后,我们发现上面的重构涉及其中,最后我们回滚了更新 我们还没有在测试环境中重现该问题以探索解决方法,因此出现了一些棘手的情况以使问题可见 以下是有关更改的详细信息。我们更新了很多触发器,但它们都非常相似,我将向您展示其中一个。

今天我们有一个非常有趣的案例,让我很困惑。简而言之,我们做了一些重构,从重复的代码中清除触发器,将其提取到单个可重用的存储过程中。我们认为这种重构不会有副作用,但我们大错特错了。发布后,我们遇到了很多死锁和性能下降,没有明显的原因。在检查了系统表以了解数据库是由什么组成的之后,我们发现上面的重构涉及其中,最后我们回滚了更新

我们还没有在测试环境中重现该问题以探索解决方法,因此出现了一些棘手的情况以使问题可见

以下是有关更改的详细信息。我们更新了很多触发器,但它们都非常相似,我将向您展示其中一个。这应该足够了,因为我已经找到了死锁图,它显示有一个死锁,其中两个进程正在执行下面显示的单触发器,并且处于死锁状态

让我从我们回滚到之前的解决方案开始,它看起来和下面显示的死锁解决方案几乎相同

CREATE TRIGGER [dbo].[TR__xyz__update_sync_publishers]
ON [dbo].[xyz]
AFTER INSERT, DELETE, UPDATE
AS 
BEGIN
    SET NOCOUNT ON;

    if(TRIGGER_NESTLEVEL() = 1)
    BEGIN
        create table #AffectedIDs (advisor_id int primary key)

        insert into #AffectedIDs
            select distinct t.id
            from
                (select id 
                 from inserted
                 inner join xyz a ON a.id = id
                 where [text] <> ''
                 union 
                 select id 
                 from inserted
                 inner join xyz a ON a.id = id
                 where [text] <> '') t

        declare @date datetime = getutcdate()
        declare @RegisteredObjectTypeID int = 2
        declare @SyncPublisherSourceID int = 1

        update pub
        set pub.master_update_date = @date
        from #AffectedIDs affected
        inner join sync_publishers pub on 
            pub.sync_registered_object_type_id = @RegisteredObjectTypeID 
            and pub.sync_publisher_source_id = @SyncPublisherSourceID
            and pub.sync_object_id = affected.advisor_id

        insert into sync_publishers (sync_object_id, sync_registered_object_type_id, sync_publisher_source_id , master_update_date)
        select 
            affected.advisor_id,
            @RegisteredObjectTypeID,
            @SyncPublisherSourceID,
            @date
        from #AffectedIDs affected
        left join sync_publishers pub on 
            pub.sync_registered_object_type_id = @RegisteredObjectTypeID
            and pub.sync_publisher_source_id = @SyncPublisherSourceID
            and pub.sync_object_id = affected.advisor_id
        where 
            pub.sync_object_id is null

        drop table #AffectedIDs
    END
END
dtInt的定义

CREATE TYPE [dbo].[dtInt] AS TABLE
(
    [value] [int] NOT NULL,
    PRIMARY KEY CLUSTERED 
    (
        [value] ASC
    )
)
最后是死锁图

<deadlock>
  <victim-list>
    <victimProcess id="processe1892fe8c8" />
  </victim-list>
  <process-list>
    <process id="processe1892fe8c8" taskpriority="0" logused="3824" waitresource="KEY: 5:72057602924150784 (4776e78e2961)" waittime="5686" ownerId="2583257965" transactionname="user_transaction" lasttranstarted="2016-10-03T08:30:42.500" XDES="0xe192b24408" lockMode="U" schedulerid="6" kpid="41296" status="suspended" spid="141" sbid="0" ecid="0" priority="0" trancount="2" lastbatchstarted="2016-10-03T08:30:42.503" lastbatchcompleted="2016-10-03T08:30:42.493" lastattention="2016-10-03T08:29:01.693" clientapp="..." hostname="..." hostpid="22572" loginname="kbuser" isolationlevel="read committed (2)" xactid="2583257965" currentdb="5" lockTimeout="4294967295" clientoption1="673316896" clientoption2="128056">
      <executionStack>
        <frame procname="63c1b4d8-1c55-4429-b057-81fb6da8f780.dbo.SyncTracker_PublishEvent" line="21" stmtstart="1178" stmtend="1680" sqlhandle="0x030005007bf23c4b5012b40092a6000001000000000000000000000000000000000000000000000000000000">
update pub
    set pub.master_update_date = @date
    from @ids affected
    inner join sync_publishers pub
    on pub.sync_registered_object_type_id = @objectTypeId 
        and pub.sync_publisher_source_id = @pubSourceId
        and pub.sync_object_id = affected.valu    </frame>
        <frame procname="63c1b4d8-1c55-4429-b057-81fb6da8f780.dbo.TR__xyz__update_sync_publishers" line="28" stmtstart="1300" stmtend="1372" sqlhandle="0x03000500f711233ddee4c60090a6000000000000000000000000000000000000000000000000000000000000">
exec SyncTracker_PublishEvent 2, @id    </frame>
        <frame procname="unknown" line="1" stmtstart="1054" stmtend="3032" sqlhandle="0x02000000912653235c5ef3529289f19ae4445e62ee1ccbc00000000000000000000000000000000000000000">
unknown    </frame>
        <frame procname="unknown" line="1" sqlhandle="0x0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000">
unknown    </frame>
      </executionStack>
    </process>
    <process id="processdfa401b848" taskpriority="0" logused="9384" waitresource="KEY: 5:72057602924150784 (1501093f83b4)" waittime="5814" ownerId="2582414029" transactionname="user_transaction" lasttranstarted="2016-10-03T08:30:09.933" XDES="0x104486ac408" lockMode="U" schedulerid="1" kpid="19548" status="suspended" spid="213" sbid="0" ecid="0" priority="0" trancount="2" lastbatchstarted="2016-10-03T08:30:53.047" lastbatchcompleted="2016-10-03T08:30:53.047" lastattention="1900-01-01T00:00:00.047" clientapp="..." hostname="..." hostpid="6196" loginname="kbuser" isolationlevel="read committed (2)" xactid="2582414029" currentdb="5" lockTimeout="4294967295" clientoption1="673316896" clientoption2="128056">
      <executionStack>
        <frame procname="63c1b4d8-1c55-4429-b057-81fb6da8f780.dbo.SyncTracker_PublishEvent" line="21" stmtstart="1178" stmtend="1680" sqlhandle="0x030005007bf23c4b5012b40092a6000001000000000000000000000000000000000000000000000000000000">
update pub
    set pub.master_update_date = @date
    from @ids affected
    inner join sync_publishers pub
    on pub.sync_registered_object_type_id = @objectTypeId 
        and pub.sync_publisher_source_id = @pubSourceId
        and pub.sync_object_id = affected.valu    </frame>
        <frame procname="63c1b4d8-1c55-4429-b057-81fb6da8f780.dbo.TR__xyz__update_sync_publishers" line="28" stmtstart="1300" stmtend="1372" sqlhandle="0x03000500f711233ddee4c60090a6000000000000000000000000000000000000000000000000000000000000">
exec SyncTracker_PublishEvent 2, @id    </frame>
        <frame procname="unknown" line="1" stmtstart="1120" stmtend="3132" sqlhandle="0x020000007414d821ed68a2ab4462b4eca6b2fdb4ba28cc350000000000000000000000000000000000000000">
unknown    </frame>
        <frame procname="unknown" line="1" sqlhandle="0x0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000">
unknown    </frame>
      </executionStack>
    </process>
  </process-list>
  <resource-list>
    <keylock hobtid="72057602924150784" dbid="5" objectname="63c1b4d8-1c55-4429-b057-81fb6da8f780.dbo.sync_publishers" indexname="IX__sync_publishers__registered_object_type_id__sync_object_id" id="lock10887a96b00" mode="X" associatedObjectId="72057602924150784">
      <owner-list>
        <owner id="processdfa401b848" mode="X" />
      </owner-list>
      <waiter-list>
        <waiter id="processe1892fe8c8" mode="U" requestType="wait" />
      </waiter-list>
    </keylock>
    <keylock hobtid="72057602924150784" dbid="5" objectname="63c1b4d8-1c55-4429-b057-81fb6da8f780.dbo.sync_publishers" indexname="IX__sync_publishers__registered_object_type_id__sync_object_id" id="lockdb7d7b8200" mode="X" associatedObjectId="72057602924150784">
      <owner-list>
        <owner id="processe1892fe8c8" mode="X" />
      </owner-list>
      <waiter-list>
        <waiter id="processdfa401b848" mode="U" requestType="wait" />
      </waiter-list>
    </keylock>
  </resource-list>
</deadlock>
开始在MERGE语句上出现死锁。可以在此处查看新的死锁图:

更新3。正在尝试合并提示

我曾尝试使用xlock和holdlock提示进行合并,但运气不好,在合并时再次出现死锁

MERGE sync_publishers2 with(xlock, holdlock) t

这是一个版本,它在并行进行了1个多小时的3个工作负载会话后似乎没有死锁。首先,我不能真正找出死锁的确切原因,但我能做的是强调死锁尝试的不同之处,它也包含了MERGE语句:下面的版本似乎可以正常工作,它使用CTE允许MERGE的ON表达式以一种只提及PK列sync_publisher_id的方式重写

示例执行计划:


尝试检查触发器主体中的触发器级别。在您的proc版本中,此代码可能会运行两次:insert into@ids select distinct t.id,从中可能会严重影响锁的持有时间。请检查更新发布的实际执行计划,并将触发器与SP中的insert into sync_publishers语句插入同步发布者。是否由于基数估计数?@RazvanSocol,谢谢你的建议!我已经用这两种情况的实际执行计划更新了帖子-看起来几乎完全相同…为什么Union子查询有两个相同的分支?为什么会有一个联合的Select Distinct[Distinct]?@EugeneD.Gubenkov,在没有阅读所有细节的情况下,尝试使用WITH HOLDLOCK提示进行合并。看见
<deadlock>
  <victim-list>
    <victimProcess id="processe1892fe8c8" />
  </victim-list>
  <process-list>
    <process id="processe1892fe8c8" taskpriority="0" logused="3824" waitresource="KEY: 5:72057602924150784 (4776e78e2961)" waittime="5686" ownerId="2583257965" transactionname="user_transaction" lasttranstarted="2016-10-03T08:30:42.500" XDES="0xe192b24408" lockMode="U" schedulerid="6" kpid="41296" status="suspended" spid="141" sbid="0" ecid="0" priority="0" trancount="2" lastbatchstarted="2016-10-03T08:30:42.503" lastbatchcompleted="2016-10-03T08:30:42.493" lastattention="2016-10-03T08:29:01.693" clientapp="..." hostname="..." hostpid="22572" loginname="kbuser" isolationlevel="read committed (2)" xactid="2583257965" currentdb="5" lockTimeout="4294967295" clientoption1="673316896" clientoption2="128056">
      <executionStack>
        <frame procname="63c1b4d8-1c55-4429-b057-81fb6da8f780.dbo.SyncTracker_PublishEvent" line="21" stmtstart="1178" stmtend="1680" sqlhandle="0x030005007bf23c4b5012b40092a6000001000000000000000000000000000000000000000000000000000000">
update pub
    set pub.master_update_date = @date
    from @ids affected
    inner join sync_publishers pub
    on pub.sync_registered_object_type_id = @objectTypeId 
        and pub.sync_publisher_source_id = @pubSourceId
        and pub.sync_object_id = affected.valu    </frame>
        <frame procname="63c1b4d8-1c55-4429-b057-81fb6da8f780.dbo.TR__xyz__update_sync_publishers" line="28" stmtstart="1300" stmtend="1372" sqlhandle="0x03000500f711233ddee4c60090a6000000000000000000000000000000000000000000000000000000000000">
exec SyncTracker_PublishEvent 2, @id    </frame>
        <frame procname="unknown" line="1" stmtstart="1054" stmtend="3032" sqlhandle="0x02000000912653235c5ef3529289f19ae4445e62ee1ccbc00000000000000000000000000000000000000000">
unknown    </frame>
        <frame procname="unknown" line="1" sqlhandle="0x0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000">
unknown    </frame>
      </executionStack>
    </process>
    <process id="processdfa401b848" taskpriority="0" logused="9384" waitresource="KEY: 5:72057602924150784 (1501093f83b4)" waittime="5814" ownerId="2582414029" transactionname="user_transaction" lasttranstarted="2016-10-03T08:30:09.933" XDES="0x104486ac408" lockMode="U" schedulerid="1" kpid="19548" status="suspended" spid="213" sbid="0" ecid="0" priority="0" trancount="2" lastbatchstarted="2016-10-03T08:30:53.047" lastbatchcompleted="2016-10-03T08:30:53.047" lastattention="1900-01-01T00:00:00.047" clientapp="..." hostname="..." hostpid="6196" loginname="kbuser" isolationlevel="read committed (2)" xactid="2582414029" currentdb="5" lockTimeout="4294967295" clientoption1="673316896" clientoption2="128056">
      <executionStack>
        <frame procname="63c1b4d8-1c55-4429-b057-81fb6da8f780.dbo.SyncTracker_PublishEvent" line="21" stmtstart="1178" stmtend="1680" sqlhandle="0x030005007bf23c4b5012b40092a6000001000000000000000000000000000000000000000000000000000000">
update pub
    set pub.master_update_date = @date
    from @ids affected
    inner join sync_publishers pub
    on pub.sync_registered_object_type_id = @objectTypeId 
        and pub.sync_publisher_source_id = @pubSourceId
        and pub.sync_object_id = affected.valu    </frame>
        <frame procname="63c1b4d8-1c55-4429-b057-81fb6da8f780.dbo.TR__xyz__update_sync_publishers" line="28" stmtstart="1300" stmtend="1372" sqlhandle="0x03000500f711233ddee4c60090a6000000000000000000000000000000000000000000000000000000000000">
exec SyncTracker_PublishEvent 2, @id    </frame>
        <frame procname="unknown" line="1" stmtstart="1120" stmtend="3132" sqlhandle="0x020000007414d821ed68a2ab4462b4eca6b2fdb4ba28cc350000000000000000000000000000000000000000">
unknown    </frame>
        <frame procname="unknown" line="1" sqlhandle="0x0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000">
unknown    </frame>
      </executionStack>
    </process>
  </process-list>
  <resource-list>
    <keylock hobtid="72057602924150784" dbid="5" objectname="63c1b4d8-1c55-4429-b057-81fb6da8f780.dbo.sync_publishers" indexname="IX__sync_publishers__registered_object_type_id__sync_object_id" id="lock10887a96b00" mode="X" associatedObjectId="72057602924150784">
      <owner-list>
        <owner id="processdfa401b848" mode="X" />
      </owner-list>
      <waiter-list>
        <waiter id="processe1892fe8c8" mode="U" requestType="wait" />
      </waiter-list>
    </keylock>
    <keylock hobtid="72057602924150784" dbid="5" objectname="63c1b4d8-1c55-4429-b057-81fb6da8f780.dbo.sync_publishers" indexname="IX__sync_publishers__registered_object_type_id__sync_object_id" id="lockdb7d7b8200" mode="X" associatedObjectId="72057602924150784">
      <owner-list>
        <owner id="processe1892fe8c8" mode="X" />
      </owner-list>
      <waiter-list>
        <waiter id="processdfa401b848" mode="U" requestType="wait" />
      </waiter-list>
    </keylock>
  </resource-list>
</deadlock>
MERGE sync_publishers2 t
USING @ids s
ON s.[value] = t.sync_object_id
    and t.sync_registered_object_type_id = @objectTypeId
WHEN MATCHED
    THEN UPDATE
        SET master_update_date = @date
WHEN NOT MATCHED
    THEN INSERT
             (sync_object_id, sync_registered_object_type_id, master_update_date)
        VALUES
             (s.[value], @objectTypeId, @date);
MERGE sync_publishers2 with(xlock, holdlock) t
CREATE PROCEDURE [dbo].[SyncTracker_PublishEvent2]
    @objectTypeId int, 
    @ids dtInt readonly
AS
BEGIN
    SET NOCOUNT ON;

    -- stop recoursive propogations
    if(TRIGGER_NESTLEVEL() > 1) RETURN;

    declare @date datetime = getutcdate()

    ;WITH sync_publishers2CTE AS
    (
        SELECT [sync_publisher_id],
                [sync_object_id],
                [sync_registered_object_type_id],
                [master_update_date]
            FROM [dbo].[sync_publishers2] 
            WHERE sync_registered_object_type_id = @objectTypeId
    )
    MERGE sync_publishers2CTE WITH (XLOCK) trg
    USING 
    (
            SELECT sp.sync_publisher_id,
                    s.Value AS sync_object_id,
                    @objectTypeId AS sync_registered_object_type_id,
                    @date AS master_update_date
                FROM @ids s 
                LEFT JOIN sync_publishers2 sp ON sp.sync_object_id = s.Value
                                                AND sp.sync_registered_object_type_id = @objectTypeId 
    ) src
    ON (trg.sync_publisher_id = src.sync_publisher_id)
    WHEN MATCHED
        THEN UPDATE
            SET trg.master_update_date = src.master_update_date
    WHEN NOT MATCHED
        THEN INSERT
                 (sync_object_id, sync_registered_object_type_id, master_update_date)
            VALUES
                 (sync_object_id, sync_registered_object_type_id, master_update_date);
END