2010-03-22 6 views
4

У меня проблема с тупиком в SQL Server, который я не смог решить.SQL deadlock on delete then bulk insert

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

По существу, сделка выглядит следующим образом

BEGIN TRANSACTION T1 
DELETE FROM [TableName] WITH(XLOCK HOLDLOCK) WHERE [Id][email protected] AND [SubId][email protected] 

INSERT BULK [TableName] (
[Id] Int 
, [SubId] Int 
, [Text] VarChar(max) COLLATE SQL_Latin1_General_CP1_CI_AS 
) WITH(CHECK_CONSTRAINTS, FIRE_TRIGGERS) 

COMMIT TRANSACTION T1 

Основная вставка только вставляет элементы, соответствующие Id и SubID делеции в той же транзакции. Кроме того, эти записи Id и SubId никогда не должны перекрываться.

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

Я добавил блокирующие подсказки XLOCK HOLDLOCK, чтобы попытаться решить проблему, но они, похоже, не помогают.

Каноническая тупиковый график этой ошибки показывает:

Подключение 1:

  • Держит RangeX-X на PK_TableName
  • ПРОВЕЛ замок IX страницу на столе
  • запрашивающей X Page привязываться таблица

Соединение 2:

  • Держит замок IX страницу на столе
  • запросов RangeX-X блокировку таблицы

Что мне нужно сделать для того, чтобы гарантировать, что эти тупики не возникают.

Я делал некоторые чтения на замках RangeX-X, и я не уверен, что полностью понимаю, что происходит с ними. Есть ли у меня какие-либо возможности, кроме блокировки всей таблицы здесь?

ответ

1

Его трудно дать вам точный ответ, не имея списка индексов/размера стола и т. Д., Однако имейте в виду, что SQL не может захватить несколько блокировок в одном экземпляре. Он будет захватывать блокировки по одному вовремя, а если другое соединение уже удерживает блокировку, и оно блокирует то, что требуется первой транзакции, у вас есть тупик.

В данном конкретном случае, есть несколько вещей, которые вы можете сделать:

  1. Убедитесь, есть индекс (Id, Subid), таким образом SQL будет в состоянии захватить блокировку одного диапазона для данных удаляется.
  2. Если тупики становятся редкими, повторите свои тупики.
  3. Вы можете подойти к этому с sledghammer и использовать TABLOCKX, который не будет тупиковой ситуации когда-либо
  4. Получить точный анализ тупиковой с помощью флага трассировки 1204 http://support.microsoft.com/kb/832524 (более информация у вас есть о фактическом тупике, тем легче работать вокруг)
2

Исходя из ответа Сэма шафрана:

  • Рассмотрим READPAST намек пропустить приостановленных замки, если @ ИД7 @ SubID является distinc
  • Рассмотрим SERIALI ZABLE и удалите XLOCK, HOLDLOCK
  • Используйте отдельный промежуточный стол для объемной вставки, затем скопируйте его с