Причина того, что процесс является жертвой взаимоблокировки

У меня есть процесс с Select, который занимает много времени для завершения, порядка 5-10 минут.
В настоящее время я не использую NOLOCK в качестве подсказки для механизма базы данных MS SQL.
В то же время у нас есть другой процесс, который делает обновления и вставляет их в одну и ту же базу данных и те же таблицы. процесс начался, недавно досрочно закончилось сообщением

SQLEXCEPTION: транзакция была заблокирована при блокировке ресурсов другим процессом и была выбрана как жертва тупика.

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

  • Может ли время, необходимое для выполнения транзакции, сделать связанный процесс более вероятным помечаемым как жертва взаимоблокировки.
  • Если я выполнил выбор с помощью подсказки NOLOCK, это устранит проблему?
  • Я подозреваю, что поле datetime, которое проверяется как часть предложения WHERE в инструкции select, вызывает медленное время поиска. Могу ли я создать индекс на основе этого поля? Целесообразно?

Ответ 1

Q1: Может ли время, которое требуется для выполнения транзакции, сделать связанный процесс более вероятным помечаемым как жертва взаимоблокировки.

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

По умолчанию Database Engine выбирает в качестве жертвы тупиковой ситуации сеанс, выполняющий транзакцию наименее дорогой для отката. В качестве альтернативы, пользователь может указать приоритет сеансов в тупиковой ситуации, используя оператор SET DEADLOCK_PRIORITY. DEADLOCK_PRIORITY может быть установлен как LOW, NORMAL или HIGH, или, альтернативно, может быть установлено любое целочисленное значение в диапазоне (от -10 до 10).

Q2. Если я выполнил выбор с помощью подсказки NOLOCK, это устранит проблему?

Нет. По нескольким причинам:

Q3. Я подозреваю, что поле datetime, которое проверяется как часть предложения WHERE в инструкции select, вызывает медленное время поиска. Могу ли я создать индекс на основе этого поля? Целесообразно?

Возможно. Причиной тупика почти наверняка будет плохо индексированная база данных. 10 минут запросов приемлемы в таких узких условиях, что я на 100% уверен, что в вашем случае неприемлемо.

С доверием 99% я заявляю, что ваш тупик обложен большим сканированием таблицы, противоречащим обновлениям. Начните с захвата тупикового графика, чтобы проанализировать причину. Вам, скорее всего, придется оптимизировать схему вашей базы данных. Прежде чем выполнять какие-либо изменения, прочитайте этот раздел "Разработка индексов" и подзаголовков.

Ответ 2

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

Ответ 3

Ответы здесь стоит попробовать, но вы также должны просмотреть свой код. В частности, прочитайте ответ Polyfun здесь: Как избавиться от тупика в приложении SQL Server 2005 и С#?

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