Eu tenho o seguinte procedimento (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 formam a chave composta para a tabela de destino. CompanyId é uma chave estrangeira para uma tabela pai. Além disso, há um índice não clusterizado em CompanyId asc, UserId asc
.
Ele é chamado de muitos threads diferentes e estou constantemente obtendo impasses entre diferentes processos que chamam essa mesma instrução. Meu entendimento era que o "with (holdlock)" era necessário para evitar erros de condição de corrida de inserção/atualização.
Presumo que dois threads diferentes estão bloqueando linhas (ou páginas) em ordens diferentes quando estão validando as restrições e, portanto, estão em um impasse.
Será esta uma suposição correta?
Qual é a melhor maneira de resolver essa situação (ou seja, sem impasses, impacto mínimo no desempenho multithread)?
(Se você visualizar a imagem em uma nova guia, ela é legível. Desculpe pelo tamanho pequeno.)
- Há no máximo 28 linhas no @datatable.
- Rastreei o código e não consigo ver em nenhum lugar onde iniciamos uma transação aqui.
- A chave estrangeira está configurada para cascatear apenas na exclusão e não houve exclusões da tabela pai.