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

106

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

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

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

  1. Может ли время, необходимое для выполнения транзакции, повысить вероятность того, что связанный процесс будет отмечен как жертва тупика.
  2. Если я выполню выбор с подсказкой NOLOCK, устранит ли это проблему?
  3. Я подозреваю, что поле datetime, которое проверяется как часть предложения WHERE в операторе select, вызывает медленное время поиска. Могу ли я создать индекс на основе этого поля? Это целесообразно?
Эллиотт
источник
Частичный ответ на пункт 1: не путайте тупик с таймаутом. Если у вас был тайм-аут, то время, затраченное на завершение одной транзакции, может быть причиной прерывания другой. Кроме того, было бы полезно знать, на каком ресурсе вы зашли в тупик (это индекс или таблица?).
NealB 05
1
SET DEADLOCK_PRIORITY HIGH ALTER DATABASE dbname SET MULTI_USER;
gstackoverflow 02

Ответы:

129

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

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

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

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

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

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

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

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

Ремус Русану
источник
Спасибо за обстоятельный ответ. Думаю, у меня все еще есть один вопрос. Почему я могу попасть в тупиковую ситуацию только в одной среде, а не в другой? Хотя софт такой же. Ваш ответ предполагает, что продолжительность выполнения запроса Select не имеет значения, и именно тот факт, что запрос Select сам по себе вызывает сбой процесса. Но тогда почему только тогда, когда выполнение запроса на выборку занимает много времени?
Elliott
4
Длина запроса не имеет значения при выборе жертвы тупика . Это имеет значение в возникновении тупика, по крайней мере, по двум причинам: 1) простая вероятность. Чем длиннее запрос, тем больше вероятность перекрытия одновременных обновлений и возникновения тупиковых ситуаций. 2) таблица большего размера может использовать совершенно другой план запроса, подверженный взаимоблокировкам.
Ремус Русану
12

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

Эллиотт
источник
34
Кто-нибудь может объяснить почему? (Волшебные решения не очень полезны)
OGrandeDiEnne
2
Этот парень объясняет это в своем посте: mssqltips.com/sqlservertip/2517/…
siga0984
6

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

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

Питер Бартон
источник
0

Хотя @ Remus Rusanu уже является отличным ответом, на случай, если кто-то с нетерпением ждет более глубокого понимания причин тупиковых ситуаций и стратегий трассировки SQL Server , я бы посоветовал вам прочитать книгу Брэда МакГихи « Как отследить взаимоблокировки с помощью SQL Server 2005 Profiler»

Хулио Нобре
источник