Тупик при удалении заявления

11

Я захожу в тупик при запуске задания SQL Server. Тупик возникает в простом операторе DELETE. Я бы подумал, что должен быть запущен запрос SELECT / UPDATE, чтобы вызвать тупик? Но похоже, что это УДАЛИТЬ / УДАЛИТЬ тупик ...

То, что я ищу, это то, почему я получаю тупик УДАЛИТЬ / УДАЛИТЬ. Это (насколько мне известно) передача в различных параметрах.

Есть идеи? Спасибо.

deadlock-list
2014-05-20 07:30:09.66 spid25s      deadlock victim=process409048
2014-05-20 07:30:09.66 spid25s       process-list
2014-05-20 07:30:09.66 spid25s        process id=process409048 taskpriority=0 logused=0 waitresource=PAGE: 12:1:7127294 waittime=4352 ownerId=629860973 transactionname=DELETE lasttranstarted=2014-05-20T07:30:05.307 XDES=0x397219620 lockMode=U schedulerid=5 kpid=3792 status=suspended spid=150 sbid=0 ecid=3 priority=0 trancount=0 lastbatchstarted=2014-05-20T07:30:05.307 lastbatchcompleted=2014-05-20T07:30:05.307 clientapp=QSQL25 hostname=MORRIS hostpid=1528 isolationlevel=read committed (2) xactid=629860973 currentdb=12 lockTimeout=4294967295 clientoption1=671088672 clientoption2=128056
2014-05-20 07:30:09.66 spid25s         executionStack
2014-05-20 07:30:09.66 spid25s          frame procname=adhoc line=1 stmtstart=68 sqlhandle=0x020000000b887a18f75d0aa07c25a9b8630fca696aa0e5d2
2014-05-20 07:30:09.66 spid25s     DELETE FROM dbo.UserDetailsData WHERE        (Username = @P1) AND (UserDate = @P2)     
2014-05-20 07:30:09.66 spid25s          frame procname=unknown line=1 sqlhandle=0x000000000000000000000000000000000000000000000000
2014-05-20 07:30:09.66 spid25s     unknown     
2014-05-20 07:30:09.66 spid25s         inputbuf
2014-05-20 07:30:09.66 spid25s        process id=process432e08 taskpriority=0 logused=0 waitresource=PAGE: 12:1:7127916 waittime=2648 ownerId=629859744 transactionname=DELETE lasttranstarted=2014-05-20T07:30:04.833 XDES=0x4c3426b50 lockMode=U schedulerid=6 kpid=5988 status=suspended spid=146 sbid=0 ecid=3 priority=0 trancount=0 lastbatchstarted=2014-05-20T07:30:04.833 lastbatchcompleted=2014-05-20T07:30:04.820 clientapp=QSQL25 hostname=MORRIS hostpid=1528 isolationlevel=read committed (2) xactid=629859744 currentdb=12 lockTimeout=4294967295 clientoption1=671088672 clientoption2=128056
2014-05-20 07:30:09.66 spid25s         executionStack
2014-05-20 07:30:09.66 spid25s          frame procname=adhoc line=1 stmtstart=68 sqlhandle=0x020000000b887a18f75d0aa07c25a9b8630fca696aa0e5d2
2014-05-20 07:30:09.66 spid25s     DELETE FROM dbo.UserDetailsData WHERE        (Username = @P1) AND (UserDate = @P2)     
2014-05-20 07:30:09.66 spid25s          frame procname=unknown line=1 sqlhandle=0x000000000000000000000000000000000000000000000000
2014-05-20 07:30:09.66 spid25s     unknown     
2014-05-20 07:30:09.66 spid25s         inputbuf
2014-05-20 07:30:09.66 spid25s        process id=process39ea562c8 taskpriority=0 logused=0 waitresource=PAGE: 12:1:7127916 waittime=4352 ownerId=629860973 transactionname=DELETE lasttranstarted=2014-05-20T07:30:05.307 XDES=0x13e0e4b50 lockMode=U schedulerid=2 kpid=7124 status=suspended spid=150 sbid=0 ecid=1 priority=0 trancount=0 lastbatchstarted=2014-05-20T07:30:05.307 lastbatchcompleted=2014-05-20T07:30:05.307 clientapp=QSQL25 hostname=MORRIS hostpid=1528 isolationlevel=read committed (2) xactid=629860973 currentdb=12 lockTimeout=4294967295 clientoption1=671088672 clientoption2=128056
2014-05-20 07:30:09.66 spid25s         executionStack
2014-05-20 07:30:09.66 spid25s          frame procname=adhoc line=1 stmtstart=68 sqlhandle=0x020000000b887a18f75d0aa07c25a9b8630fca696aa0e5d2
K09
источник
5
Нет, тупик может возникнуть в других сценариях за пределами SELECT / UPDATE. Все, что вам действительно нужно, - это два процесса, каждый из которых нуждается в ресурсе, который держит другой. (1) Являются ли операторы DELETE частью более крупной транзакции? (2) Можете ли вы опубликовать где-нибудь тупиковый XML вместо дерьмового журнала ошибок?
Аарон Бертран
Не могли бы вы опубликовать схему таблицы dbo.UserDetailsDataвключения всех индексов? Кроме того, вы знаете, если эти операторы вызываются с одинаковыми параметрами? Учитывая, что в обоих журналах используется нулевой журнал, мне интересно, нужно ли вам всего лишь сериализовать вызовы, потому что они наступают друг на друга.
Джон Зигель
Как я могу получить XML? Получил ошибку из журналов ошибок SQL Server. Заявления вызываются с разными параметрами. Недавно мы добавили несколько отфильтрованных индексов, которые фильтруются в поле UserDate.
K09
Поймать событие тупикового графа в Профилировщике. Затем, после того, как вы его поймаете, щелкните правой кнопкой мыши по строке -> извлечь данные о событии -> где-нибудь сохранить как .xdl и опубликовать его содержимое (это xml) на Pastebin (или где-то похожем).
Мариан
1
Привет, XML опубликован здесь ... надеюсь, это поможет! dl.dropboxusercontent.com/u/16953128/DeadlockTest.xdl
K09

Ответы:

14

То, что я ищу, это то, почему я получаю тупик УДАЛИТЬ / УДАЛИТЬ.

Похоже, тупик возникает из-за:

  1. spid 54 ecid 0получает Uблокировку страницы update ( )PAGE: 12:1:5147422
  2. spid 166 ecid 3запрашивает Uблокировку страницы update ( ) на той же странице и блокируется
  3. spid 54 ecid 2запрашивает обновление ( U) блокировки страницы на той же странице ...

Страницы предварительно выбираются для запроса с блокировками обновления, полученными ecid 0. Это шаг 1 выше. На шаге 3 дочерний поток того же параллельного запроса ( ecid 2) запрашивает ту же блокировку. Обычно это не будет проблемой. SQL Server знает ecid 0и ecid 2является потоками одного и того же родительского процесса. К сожалению, шаг 2 мешает этому, и в результате возникает тупик.

Тем не менее, вам не нужно особо беспокоиться о том, почему возникает тупик, важный вопрос - как вам этого избежать. Ответ заключается в предоставлении эффективного пути доступа для DELETE. Оператор должен найти строки WHERE Username = @P1 AND UserDate = @P2, поэтому у вас должен быть индексированный ключ для этих столбцов.

И, конечно, у вас есть такой индекс. Реальный вопрос почему ваши проблемы начались происходят после добавления отфильтрованных индексов.

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

Вы можете найти более подробную информацию об этом и рабочий пример в этом посте .

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

Ответ заключается в том, чтобы сделать одно из следующего:

  1. Удалить отфильтрованные индексы
  2. Добавить отфильтрованный ключ индекса / столбцы включения / предиката к существующему индексу имени / даты
  3. Принудительный широкий план обновления (нет поддерживаемого способа сделать это)
  4. Запустите запрос под изоляцией моментального снимка (не RCSI)

Вариант 2 будет моим сильным предпочтением.

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

Пол Уайт 9
источник