Как автоматически перезапустить заблокированную транзакцию? (ASP.NET MVC / SQL Server) - PullRequest
5 голосов
/ 31 мая 2010

У меня есть очень популярный сайт в ASP.NET MVC / SQL Server, и, к сожалению, возникает много тупиков.Пока я пытаюсь выяснить, почему они происходят через профилировщик SQL, мне интересно, как я могу изменить поведение SQL Server по умолчанию при выполнении взаимоблокировок.) что вызвало проблемы вместо отображения экрана ошибки?

Ответы [ 5 ]

10 голосов
/ 15 мая 2013

Ответ Ремуса в корне ошибочен.Согласно https://stackoverflow.com/a/112256/14731 последовательный порядок блокировки не предотвращает взаимоблокировки.Лучшее, что мы можем сделать, - это уменьшить их частоту.

Он неправ в двух моментах:

  1. Подразумевается, что взаимоблокировки можно предотвратить.Вы найдете статьи Microsoft и IBM о сокращении частоты взаимоблокировок.Нет, где они утверждают, что вы можете полностью их предотвратить.
  2. Подразумевается, что все взаимоблокировки требуют от вас переоценки состояния и принятия нового решения.Совершенно правильно повторять некоторые действия на уровне приложения, если вы путешествуете достаточно далеко до точки принятия решения.

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

6 голосов
/ 31 мая 2010

Вы лаете не на то дерево. Вам никогда не удастся выполнить автоматические попытки взаимоблокировки с помощью механизма SQL, такая концепция в корне неверна. Само определение тупика состоит в том, что состояние, на котором вы основываете свое решение, изменилось на , поэтому вам необходимо снова прочитать состояние и принять новое решение. Если ваш процесс заблокирован, по определению другой процесс имеет выиграл взаимоблокировки, и он измерил изменил то, что вы прочитали.

Ваш only должен сосредоточиться на выяснении причин возникновения взаимоблокировок и устранении причины. Неизбежно, причиной станет запрос, который сканирует больше данных, чем должен. Хотя верно и то, что могут возникать другие типы тупиков, я уверен, что это не ваш случай. Многие проблемы будут решены путем развертывания соответствующих индексов. Некоторые проблемы отправят вас обратно на чертежную доску, и вам придется пересмотреть свои требования.

Существует множество ресурсов для определения и устранения тупиков:

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

2 голосов
/ 31 мая 2010

Многочисленные тупики часто указывают на то, что у вас либо нет правильных индексов, и / или что ваша статистика устарела У вас есть регулярные плановые перестройки индекса как часть обслуживания?

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

catch (SqlException ex) 
{ 
    if (ex.Number == 1205) 
    { 
        // Handle Deadlock by retrying save...
    } 
    else 
    {
        throw; 
    }
} 

Другой вариант - повторить попытку в хранимых процедурах. Вот пример этого: Использование TRY ... CATCH в Transact-SQL

1 голос
/ 31 мая 2010

Один вариант в дополнение к предложенным Митчем и Ремусом, поскольку ваши комментарии предполагают, что вы ищете быстрое решение. Если вы можете идентифицировать запросы, участвующие в взаимоблокировках, вы можете повлиять на то, какие из задействованных запросов откатились, а какие продолжают, установив DEADLOCK_PRIORITY для каждого запроса, пакета или хранимой процедуры.

Глядя на ваш пример в комментарии к ответу Митча:

Скажем, тупик возникает на странице A, но страница B пытается получить доступ к заблокированные данные. Ошибка будет отображается на странице B, но это не так означает, что тупик произошел на страница B. Это все еще произошло на странице A.

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

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

0 голосов
/ 21 октября 2016

в некоторых случаях вы можете сделать ниже.Между началом транса и коммитом есть все или ничего.Поэтому либо @errorcode принимает значение 0 и завершает цикл, либо, в случае сбоя, уменьшает счетчик на 1 и повторяет попытку.Это может не сработать, если вы предоставляете переменные для кода извне begin tran / commit.Просто идея:)

declare @errorcount int = 4 -- retry number
while @errorcount >0
begin
begin tran 
<your code here>
set @errorcount =0
commit 
set @errorcount=@errorcount-1
end
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...