SQL тупик при удалении, затем массовая вставка - PullRequest
4 голосов
/ 23 марта 2010

У меня проблема с тупиком в SQL Server, которую мне не удалось устранить.

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

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

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

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 Page Lock на столе
  • Запрос блокировки X-страницы на столе

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

  • Держит IX Page Lock на столе
  • Запросы на блокировку RangeX-X на столе

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

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

Ответы [ 2 ]

2 голосов
/ 28 марта 2010

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

  • Рассмотрим подсказку READPAST, чтобы пропустить все удерживаемые блокировки, если @ ID7 @ SubID имеет значение
  • Рассмотрим SERIALIZABLE и удалите XLOCK, HOLDLOCK
  • Используйте отдельную промежуточную таблицу для массовой вставки, затем скопируйте из нее
1 голос
/ 23 марта 2010

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

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

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