sql - 更新查询死锁仅在两个以上事务同时发生时
问题描述
在编写一些用于连接产品数据库的 SQL Server 更新查询时,我遇到了这样一种情况:如果具有这些更新的两个事务同时运行,一切都很好 - 但是当两个以上的事务试图同时更新同一个表时,其中一些陷入僵局。
我将问题分解为对表定义的“UNIQUE NONCLUSTERED”约束。当我删除此约束时,所有事务都将等待其所需的资源并在没有错误的情况下完成。
这是我重现问题的示例代码:
CREATE TABLE [dbo].[profiles]
(
[ProfileID] [int] IDENTITY(1,1) NOT NULL,
[ProfileName] [nvarchar](255) NOT NULL,
[GroupFK] [int] NULL
CONSTRAINT [PK_Profile]
PRIMARY KEY CLUSTERED ([ProfileID] ASC)
WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF,
IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON,
ALLOW_PAGE_LOCKS = ON, FILLFACTOR = 80) ON [PRIMARY],
-- !!! [UI_UniqueNameInGroup] seems problematic for me because i get deadlocks when executing more than two transactions at once !!!
CONSTRAINT [UI_UniqueNameInGroup]
UNIQUE NONCLUSTERED ([GroupFK] ASC, [ProfileName] ASC)
WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF,
IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON,
ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY]
INSERT INTO profiles (ProfileName) VALUES ('PROFILE_99')
INSERT INTO profiles (ProfileName) VALUES ('PROFILE_88')
INSERT INTO profiles (ProfileName) VALUES ('PROFILE_77')
INSERT INTO profiles (ProfileName) VALUES ('PROFILE_66')
这些是我的交易样本:
BEGIN TRAN
UPDATE profiles
SET ProfileName = 'NewProfile_99'
WHERE ProfileID = 4
WAITFOR DELAY '00:00:05.000'
COMMIT TRAN
BEGIN TRAN
UPDATE profiles
SET ProfileName = 'NewProfile_66'
WHERE ProfileID = 1
WAITFOR DELAY '00:00:05.000'
COMMIT TRAN
BEGIN TRAN
UPDATE profiles
SET ProfileName = 'NewProfile_88'
WHERE ProfileID = 3
WAITFOR DELAY '00:00:05.000'
COMMIT TRAN
BEGIN TRAN
UPDATE profiles
SET ProfileName = 'NewProfile_77'
WHERE ProfileID = 2
WAITFOR DELAY '00:00:05.000'
COMMIT TRAN
这是我的死锁图:
请通过向我解释这个问题来帮助我 - 我不明白为什么只有在同时执行两个以上的事务时才会发生死锁。
我也很高兴为此找到一个可行的解决方案。
我这边有解决方案(不更改数据库方案)吗?
解决方案
更改约束 [UI_UniqueNameInGroup] 以仅允许行锁:
CONSTRAINT [UI_UniqueNameInGroup] UNIQUE NONCLUSTERED ([GroupFK] ASC, [ProfileName] ASC)
WITH (PAD_INDEX = OFF,
STATISTICS_NORECOMPUTE = OFF,
IGNORE_DUP_KEY = OFF,
ALLOW_ROW_LOCKS = ON,
ALLOW_PAGE_LOCKS = OFF
) ON [PRIMARY]
这会导致问题,因为如果您拒绝页锁和行锁,那么您会强制 SQL Server 使用表锁,但其他会话已经设置了表锁。
推荐阅读
- scala - 一些 RDD 操作因 Java IllegalArgumentException 而失败
- mysql - 如何获得列的所有值的乘积?
- tfsbuild - TFS 构建定义中的“队列 Jenkins 作业”中的“取消链接”按钮有什么作用
- mysql - LEFT OUTER JOIN 与第二张表上的 WHERE 子句,不影响第一张表
- c# - 当我第一次输入输入(名称)时,消息不显示名称。我必须再次按 Enter 才能显示带有名称的消息
- bitbucket - Atlassian JavaScript 加载错误我们尝试加载脚本但出了点问题
- netsuite - 如何使用 java api 从 Netsuite 获取项目列表
- http-headers - Slim3 如何管理混合内容类型错误
- docker - Ubuntu,shopsys 通过作曲家,码头安装,仍然崩溃
- c# - 如何使用json将数据传递给ajax函数?