【问题标题】:Deadlock on update in the same table on Azure with pagelock使用页面锁在 Azure 上的同一表中更新时出现死锁
【发布时间】:2020-12-14 11:26:37
【问题描述】:

我有一个显示 Azure DB 上的事件的表。事件发生得非常频繁。他们正在添加,然后正在更新。

更新查询如下所示:

SET [DeactivationEventId] = @EventId, [Deactivated] = 1, [Type] = @DeactivationType
WHERE [DeactivationEventId] IS NULL
AND [ItemId] = @ItemId
AND [Id] <> @EventId

图表如下所示:

  <victim-list>
    <victimProcess id="process1752f0bbc28" />
  </victim-list>
  <process-list>
    <process id="process1752f0bbc28" taskpriority="0" logused="888" waitresource="PAGE: 6:1:667 " waittime="4144" ownerId="7884216" transactionname="user_transaction" lasttranstarted="2020-12-14T01:39:04.073" XDES="0x1753ad74428" lockMode="S" schedulerid="2" kpid="64600" status="suspended" spid="83" sbid="2" ecid="0" priority="0" trancount="2" lastbatchstarted="2020-12-14T01:39:04.073" lastbatchcompleted="2020-12-14T01:39:04.073" lastattention="1900-01-01T00:00:00.073" clientapp="Core .Net SqlClient Data Provider" hostname="RD00155D55DC34" hostpid="8768" loginname="westbrookb" isolationlevel="read uncommitted (1)" xactid="7884216" currentdb="6" currentdbname="Rythmos" lockTimeout="4294967295" clientoption1="671088672" clientoption2="128056">
      <executionStack>
        <frame procname="unknown" queryhash="0xb5d19baa56c298af" queryplanhash="0xa0741009000fbf64" line="1" stmtstart="102" stmtend="558" sqlhandle="0x020000007676e21a17f941df30c67e9f52cb3adb4dbf4e800000000000000000000000000000000000000000">
unknown    </frame>
        <frame procname="unknown" queryhash="0x0000000000000000" queryplanhash="0x0000000000000000" line="1" sqlhandle="0x0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000">
unknown    </frame>
      </executionStack>
      <inputbuf>
(@EventId int,@DeactivationType int,@ItemIdbigint)UPDATE [dbo].[Events] WITH (ROWLOCK)
SET [DeactivationEventId] = @EventId, [Deactivated] = 1, [Type] = @DeactivationType
WHERE [DeactivationEventId] IS NULL
AND [ItemId] = @ItemId
AND [Id] <> @EventId</inputbuf>
    </process>
    <process id="process17537256ca8" taskpriority="0" logused="1528" waitresource="PAGE: 6:1:667 " waittime="4141" ownerId="7884219" transactionname="user_transaction" lasttranstarted="2020-12-14T01:39:04.083" XDES="0x17541f1c428" lockMode="S" schedulerid="3" kpid="45516" status="suspended" spid="85" sbid="2" ecid="0" priority="0" trancount="2" lastbatchstarted="2020-12-14T01:39:04.087" lastbatchcompleted="2020-12-14T01:39:04.080" lastattention="1900-01-01T00:00:00.080" clientapp="Core .Net SqlClient Data Provider" hostname="RD0003FF811932" hostpid="8012" loginname="westbrookb" isolationlevel="read uncommitted (1)" xactid="7884219" currentdb="6" currentdbname="Rythmos" lockTimeout="4294967295" clientoption1="671088672" clientoption2="128056">
      <executionStack>
        <frame procname="unknown" queryhash="0xb5d19baa56c298af" queryplanhash="0xa0741009000fbf64" line="1" stmtstart="102" stmtend="558" sqlhandle="0x020000007676e21a17f941df30c67e9f52cb3adb4dbf4e800000000000000000000000000000000000000000">
unknown    </frame>
        <frame procname="unknown" queryhash="0x0000000000000000" queryplanhash="0x0000000000000000" line="1" sqlhandle="0x0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000">
unknown    </frame>
      </executionStack>
      <inputbuf>
(@EventId int,@DeactivationType int,@ItemIdbigint)UPDATE [dbo].[Events] WITH (ROWLOCK)
SET [DeactivationEventId] = @EventId, [Deactivated] = 1, [Type] = @DeactivationType
WHERE [DeactivationEventId] IS NULL
AND [ItemId] = @ItemId
AND [Id] <> @EventId</inputbuf>
    </process>
  </process-list>
  <resource-list>
    <**pagelock** fileid="1" pageid="667" dbid="6" subresource="FULL" objectname="065e5285-8d87-4534-93bb-20d8770ae630.dbo.WirepasDeviceEvents" id="lock174acf59300" mode="IX" associatedObjectId="72057594085638144">
      <owner-list>
        <owner id="process17537256ca8" mode="IX" />
        <owner id="process17537256ca8" mode="S" requestType="convert" />
      </owner-list>
      <waiter-list>
        <waiter id="process1752f0bbc28" mode="S" requestType="convert" />
      </waiter-list>
    </pagelock>
    <**pagelock** fileid="1" pageid="667" dbid="6" subresource="FULL" objectname="065e5285-8d87-4534-93bb-20d8770ae630.dbo.WirepasDeviceEvents" id="lock174acf59300" mode="IX" associatedObjectId="72057594085638144">
      <owner-list>
        <owner id="process1752f0bbc28" mode="IX" />
        <owner id="process1752f0bbc28" mode="S" requestType="convert" />
      </owner-list>
      <waiter-list>
        <waiter id="process17537256ca8" mode="S" requestType="convert" />
      </waiter-list>
    </pagelock>
  </resource-list>
</deadlock>

我在这张表上有四个非聚集索引。 这是为了避免这种僵局:

(
    [DeactivationEventId] ASC,
    [ItemId] ASC,
    [Id] ASC
)WITH (STATISTICS_NORECOMPUTE = OFF, DROP_EXISTING = OFF, ONLINE = OFF) ON [PRIMARY]
GO

有很多警报插入,然后在毫秒内更新: **2020-12-14 01:38:00.180

2020-12-14 01:38:00.203**

我的问题。如果我用两个查询分开它:

select Id 
from [dbo].[Events] WITH (NoLock)
WHERE [DeactivationEventId] IS NULL
AND [ItemId] = @ItemId
AND [Id] <> @EventId
SET [DeactivationEventId] = @EventId, [Deactivated] = 1, [Type] = @DeactivationType
WHERE Id = @Id

为了避免页面锁定。 这是执行计划:

你怎么看?

已编辑。

现在分离请求确实有帮助。我现在没有陷入僵局。

【问题讨论】:

  • 如果您可以指定您使用的是 SQL Server 还是 SQL Azure,这将很有帮助。它们默认使用不同的锁定模式(后者使用 RCSI)。在任何情况下,您都可以通过针对这种情况的 updlock 提示来避免更新-更新死锁。 (查询计划有助于调试,因此您可以更好地查看死锁路径)
  • 正题。天蓝色。我将在这里添加一个查询计划。

标签: sql-server azure azure-sql-database deadlock database-deadlocks


【解决方案1】:

在图中,您可以看到死锁图的两方是相同的查询计划(具有相同的哈希,因此很可能是相同的计划)。您的重写正在寻找您要更新的特定行,然后执行“宽”更新计划来更新每个索引。它会在每个 b-tree/heap/etc 上锁定,因为它会触及每一行的计划中的内容。我假设您正在使用自动提交事务,因为您没有提及任何内容。

您碰巧通过将选择部分(可能会扫描许多行,但我无法确定计划)移出获取更新所需的 U 锁的查询,从而避免了重写中的死锁. (S 锁与其他 S 锁兼容,但与 U 锁不兼容,因此当该查询的另一个实例具有 S 锁时尝试获取 U 锁的并发查询可能会导致死锁。

避免死锁的其他方法包括在原始的、更大的更新查询上添加一个 UPDLOCK 提示。对于读取的每一行,这将使用 U 锁而不是 S 锁(即使它不会被更新)。您选择的模式可能非常适合您的应用程序,但如果您即使在单行情况下同时执行相同的查询(或针对同一个表的类似查询,每个都尝试执行单点搜索),也会出现死锁,有些情况其中不同的查询计划可以为同一个表中的索引以不同的顺序锁定。例如,如果查询 1 在 index1 上锁定,然后聚集索引和查询 2 在聚集索引上锁定,然后在索引 1 上锁定,这些也可能死锁。这种模式可以通过 UPDLOCK 方法修复。

【讨论】:

  • 太棒了。谢谢你的详细解释。
  • 通过 id 将访问拆分为选择/更新确实有帮助。谢谢。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-05-07
  • 1970-01-01
  • 2018-08-05
  • 2020-01-26
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多