Как взаимные блокировки обнаруживаются и сообщаются в СУБД?

8

Мне дали этот вопрос типа эссе во время интервью, но я не получил работу. Полный вопрос был следующим:

Как взаимные блокировки обнаруживаются и сообщаются в СУБД? За что отвечает владелец транзакции и разработчик приложения в сценариях обнаружения и предотвращения?

Shadowcaz
источник

Ответы:

13

В SQL Server существует отдельный поток, который периодически (по умолчанию 5 секунд, меньший интервал, если только что обнаружена взаимоблокировка) проверяет список ожиданий любых циклов. Т.е. он идентифицирует ресурс, который ожидает поток, затем он находит владельца этого ресурса и рекурсивно находит, какой ресурс этот поток в свою очередь ожидает, тем самым идентифицируя потоки, которые ждут ресурсы друг друга.

Если обнаружен тупик, то жертва выбирается для убийства с использованием этого алгоритма:

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

Вы можете найти более подробную информацию об обнаружении взаимоблокировки серверов SQL здесь: http://msdn.microsoft.com/en-us/library/ms178104.aspx



Владелец транзакции / разработчик приложения несет ответственность за минимизацию рисков возникновения взаимоблокировок и выполнение что они должны:

  1. Сделайте транзакции максимально короткими. Например, не показывайте форму входа после запуска транзакции и ждите ввода пользователя, вместо этого соберите всю необходимую информацию и запустите транзакцию.
  2. Используйте минимально возможный уровень изоляции, например, не устанавливайте сериализуемость, когда вы просто хотите временно показать некоторые значения пользователю. Обратите внимание, что установка правильного уровня изоляции является наукой сама по себе и выходит за рамки этого ответа.
  3. Если вы стали жертвой тупика, то есть вы получили ошибку # 1205, то прозрачно перезапустите транзакцию для вашего пользователя. Поскольку другая конкурирующая транзакция теперь, как мы надеемся, получила ресурсы, которые она ждала и завершила, не похоже, что вы снова столкнетесь с тем же тупиком.
Андреас Агрен
источник
4. Получайте ресурсы и последовательно выполняйте обновление / удаление / вставку шаблонов в одном и том же порядке по всему приложению.
ErikE
3
@ErikE часто невозможно / практически невозможно «последовательно выполнять обновление / удаление / вставку шаблонов в одном и том же порядке по всему приложению», хотя этот сомнительный совет очень популярен в Интернете. Подробности здесь: sqlblog.com/blogs/alexander_kuznetsov/archive/2010/01/15/…
AK
1
Хорошие моменты. Но я все еще думаю, что эти усилия стоят того, поскольку у них нет иллюзий, что это всегда будет возможно или всегда решит проблему. Родитель / потомок интересны, как насчет каскадного удаления или получения блокировки обновления для родительских строк? И если вы делаете слияния без MERGE, почему бы не быть последовательным? Я делаю удалить-> обновить-> вставить лично.
ErikE
1
@AlexKuznetsov: Это не решающая пуля, но не должна быть отклонена. Я уменьшил (но не устранил) взаимные блокировки таким образом: посредством статического анализа часто выполняемого кода, который делал взаимоблокировки каждый день или 7. Я бы предложил применить «преждевременную оптимизацию» и т. Д.
gbn
Я не согласен с рекомендацией № 3. Когда мы повторяем попытки после взаимоблокировок, мы, скорее всего, перезапишем изменения других процессов. Нам нужно знать, что очень вероятно, что кто-то еще изменил данные, которые мы намеревались изменить. Особенно, если все читатели работают в условиях изоляции моментальных снимков, тогда читатели не могут быть вовлечены в тупики, что означает, что все стороны, участвующие в тупике, являются авторами, которые модифицировали или пытались изменить одни и те же данные. Если мы просто перехватываем исключение и автоматически повторяем попытку, мы можем перезаписать чужие изменения. Это называется потерянными обновлениями, и это обычно неправильно.
AK