【发布时间】:2021-01-11 03:46:13
【问题描述】:
我有一个表,其中有 1 到 500 万条记录作为批处理进入,然后在它们上运行一堆存储过程,以更新和删除批处理中的记录。 所有这些存储过程都使用两个字段进行选择性,因此它们只在该批次中的记录上运行。 这两个字段都在非聚集索引中。 有时会同时运行多个批次,并且我在批次之间不断发生死锁,我认为是由于锁定升级。 试图弄清楚是否有一种方法可以解决这个问题,而无需完全重新设计以对每个批次使用专用表。禁用页面锁定是否会带来更多麻烦?
附加信息:
表结构和索引示例(真实的列比这个多很多)
CREATE TABLE [dbo].[TempImport](
[UID] [int] IDENTITY(1,1) NOT NULL,
[EID] [int] NULL,
[EXTID] [int] NULL,
[COL1] [varchar](50) NULL,
[COL2] [varchar](50) NULL,
CONSTRAINT [PK_TempImport] PRIMARY KEY CLUSTERED
(
[UID] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON, OPTIMIZE_FOR_SEQUENTIAL_KEY = OFF) ON [PRIMARY]
) ON [PRIMARY]
GO
CREATE NONCLUSTERED INDEX [IX_TempImport_Main] ON [dbo].[TempImport]
(
[EID] ASC,
[EXTID] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, SORT_IN_TEMPDB = OFF, DROP_EXISTING = OFF, ONLINE = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON, OPTIMIZE_FOR_SEQUENTIAL_KEY = OFF) ON [PRIMARY]
GO
存储过程中的查询类型如下所示:
update TempImport set COL1 = 'foo' where EID = @EID and EXTID = @EXT and COL2='bar'
批处理完成时发生的最后一件事是这样的:
Delete from TempImport where EID = @EID and EXTID = @EXT
死锁通常是存储过程中的删除和更新。
如果有其他有用的信息请告诉我
【问题讨论】:
-
使用 MS SQL 2019
-
Brent Ozar 最近做了一个nice video on deadlocks。它可能对此有一些想法。这是 45 分钟,但我发现它有助于理解它们以及如何修复它们。正如您所说,表很可能被锁定 - 我相信如果 SQL Server 更新表中超过 5000 行,它会将锁升级为全表锁。从视频中我不清楚的一件事是,在一个事务(或几个较小的事务)中进行批处理是否会克服死锁。
-
谢谢,我会看看那个视频。我当时的想法是以某种方式将更新和删除分解成更小的块,但在处理数百万条记录时似乎效率会低得多。
标签: sql sql-server database-deadlocks