Как решить эту проблему взаимоблокировки?

Я столкнулся с проблемой взаимоблокировки synchronizing таблицы несколько раз за короткий промежуток времени. Под синхронизацией я подразумеваю следующие действия:

  1. Вставьте данные для синхронизации во временную таблицу
  2. Обновить существующие записи в целевой таблице
  3. Вставить новые записи в целевую таблицу
  4. Удаление записей, которых нет в таблице синхронизации при определенных обстоятельствах
  5. Скиньте временную таблицу

Для операторов INSERT и DELETE я использую LEFT JOIN, похожий на:

INSERT INTO destination_table (fk1, fk2, val1)
FROM #tmp
LEFT JOIN destination_table dt ON dt.fk1 = #tmp.fk1
   AND dt.fk2 = #temp.fk2
WHERE dt.pk IS NULL;

Граф взаимоблокировок сообщает, что первичный ключ таблицы назначения находится под монопольной блокировкой. Я предполагаю, что приведенный выше запрос вызывает блокировку таблицы или страницы вместо блокировки строки. Как бы я это подтвердил?

Я мог бы переписать приведенный выше запрос с помощью команды IN, EXIST или EXCEPT. Есть ли дополнительные способы рефакторинга кода? Избежит ли рефакторинг с использованием любой из этих команд проблему взаимоблокировки? Какой из них будет лучшим? Я предполагаю EXCEPT.


person anon    schedule 31.01.2015    source источник
comment
Все это делается в транзакции? Какой уровень изоляции транзакций вы используете? Есть ли другие действия, использующие целевую таблицу?   -  person HABO    schedule 01.02.2015


Ответы (1)


Ну, при нормальных обстоятельствах я мог бы довольно хорошо выполнить сценарий. Ниже приведен тестовый сценарий, который я создал. Вы пробуете что-то еще?

drop table #destination_table
drop table #tmp

Declare @x int=0

create table #tmp(fk1 int, fk2 int, val int)

set @x=2

while (@x<1000)
begin
    insert into #tmp
    select @x,@x,100
    set @x=@x+3
end

create table #destination_table(fk1 int, fk2 int, val int)
while (@x<1000)
begin
    insert into #destination_table
    select @x,@x,100
    set @x=@x+1
end



INSERT INTO #destination_table (fk1, fk2, val)
select t.*
FROM #tmp t
LEFT JOIN #destination_table dt ON dt.fk1 = t.fk1
     AND dt.fk2 = t.fk2
WHERE dt.fk1 IS NULL
person UVData    schedule 01.02.2015
comment
Поскольку в вашем тесте используются только локальные временные таблицы, доступ к которым осуществляется через одно соединение, немного меньше вероятность возникновения тупиковой ситуации. - person HABO; 01.02.2015