如何防止 LCK_M_IX 在以下删除和插入查询上等待/锁定

Cat*_*tNZ 2 sql-server locking

*编辑:结果证明这里的答案中没有任何解决方案,我在Python中使用SQLAlchemy,它是一个ORM。我在事务中执行下面的删除语句,但从未提交它。这导致发生大约 10 个打开的事务,最终所有事务都需要回滚,从而锁定整个表,直到回滚完成。

给定以下表结构,将使用最近日期时间的 update_time 连续插入记录。与数据库的单独连接会定期修剪日期超过 2 周的旧记录。

表结构:

表结构

以下插入运行非常频繁,具有不同的值:

插入语句

重复以下删除语句直到需要为止,然后立即运行 select 以查看该过程是否完成

delete top(5000) from trade_options with (READPAST) where update_time < '<Two Weeks Ago>'
Run Code Online (Sandbox Code Playgroud)

活动监视器显示删除正在锁定,插入正在等待(LCK_M_IX):

活动监视器的图像

谢谢

**编辑:这是作为脚本输出的索引/键

CREATE NONCLUSTERED INDEX [IX_order_option] ON [dbo].[order_option]
(
    [update_time] DESC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, SORT_IN_TEMPDB = OFF, DROP_EXISTING = OFF, ONLINE = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
GO

ALTER TABLE [dbo].[order_option] ADD PRIMARY KEY CLUSTERED 
(
    [exchange_id] ASC,
    [symbol] ASC,
    [update_time] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, SORT_IN_TEMPDB = OFF, IGNORE_DUP_KEY = OFF, ONLINE = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
GO
Run Code Online (Sandbox Code Playgroud)

sep*_*pic 5

您的问题的名称为lock escalation。您可以在此处阅读更多相关内容:如何解决 SQL Server 中锁升级引起的阻塞问题

默认情况下,SQL Server 将获取尽可能细粒度的锁,以获得最大的并发性。在大多数情况下,这意味着 SQL Server 将获取行(RID 或 KEY)锁。SQL Server 可以在单个表中的数据上获取数百或数千个单独的锁,而不会造成任何问题。然而,在某些情况下,如果 SQL Server 确定查询将访问聚集索引中的一系列行,则它可能会获取页锁。毕竟,如果要访问页面上的每一行,则管理单个页面锁比管理数十或数百个行锁更容易。在其他情况下,主要是当没有可用索引来帮助处理查询时,SQL Server 可能会在处理查询开始时锁定整个表。

indexes在你的情况下,我怀疑表上有一些(这意味着delete也获取了它们的锁)或者你在其中进行了删除transaction(这意味着所有的都locks被保留到了末尾transaction)。在这种情况下会发生这种情况:

当任何单个会话在单个语句中获取超过 5,000 个锁时, SQL Server 将升级锁。在这种情况下,选择哪个会话将其锁升级并不具有随机性;这是获取锁的会话。

因此,您应该摆脱包装transaction(如果存在),或减少batch size到较小的包装,或lock escatation在此表上禁用:

alter table order_option
set ( lock_escalation = disable )
Run Code Online (Sandbox Code Playgroud)

您认为将删除批次降低到 5000 以下,或者删​​除索引会有帮助吗?在删除索引的情况下,这不会大大减慢删除速度吗?

你不应该放弃这个index,它可以帮助你delete

你可以批量尝试一下2000 rows,应该会有帮助。

我不知道与此相关的查询类型table,但使用clustered indexonupdate_timePKas可能是有意义的nonclustered