我有以下过程(SQL Server 2008 R2):
create procedure usp_SaveCompanyUserData
@companyId bigint,
@userId bigint,
@dataTable tt_CoUserdata readonly
as
begin
set nocount, xact_abort on;
merge CompanyUser with (holdlock) as r
using (
select
@companyId as CompanyId,
@userId as UserId,
MyKey,
MyValue
from @dataTable) as newData
on r.CompanyId = newData.CompanyId
and r.UserId = newData.UserId
and r.MyKey = newData.MyKey
when not matched then
insert (CompanyId, UserId, MyKey, MyValue) values
(@companyId, @userId, newData.MyKey, newData.MyValue);
end;
CompanyId、UserId、MyKey 构成目标表的复合键。CompanyId 是父表的外键。此外,还有一个非聚集索引CompanyId asc, UserId asc
。
它是从许多不同的线程调用的,并且我一直在调用同一语句的不同进程之间遇到死锁。我的理解是“with (holdlock)”对于防止插入/更新竞争条件错误是必要的。
我假设两个不同的线程在验证约束时以不同的顺序锁定行(或页面),因此是死锁。
这是一个正确的假设吗?
解决这种情况的最佳方法是什么(即没有死锁,对多线程性能的影响最小)?
(如果您在新选项卡中查看图像,它是可读的。对不起,小尺寸。)
- @datatable 中最多有 28 行。
- 我已经追溯了代码,我看不到我们在这里开始交易的任何地方。
- 外键设置为仅在删除时级联,并且没有从父表中删除。