SQL Server блокируется между выбором / обновлением или множественным выбором - PullRequest
37 голосов
/ 19 марта 2009

Вся документация о взаимоблокировках SQL Server говорит о сценарии, в котором операция 1 блокирует ресурс A, затем пытается получить доступ к ресурсу B, а операция 2 блокирует ресурс B и пытается получить доступ к ресурсу A.

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

Это происходит в SQL Server 2005, но я не думаю, что это имеет значение.

Ответы [ 7 ]

20 голосов
/ 25 марта 2009

Это может произойти, потому что выборка блокирует два разных индекса, в то время как обновление блокирует те же индексы в обратном порядке. Для выбора требуется два индекса, потому что первый индекс не охватывает все столбцы, к которым он должен получить доступ; обновление требует двух индексов, потому что если вы обновляете ключевой столбец индекса, вам нужно его заблокировать.

http://blogs.msdn.com/bartd/archive/2006/09/25/770928.aspx имеет фантастическое объяснение. Предлагаемые исправления включают в себя добавление индекса, охватывающего все столбцы, в которых нуждается выбор, переключение на изоляцию моментальных снимков или явное принуждение выбора захватить блокировку обновления, которая обычно не требуется.

13 голосов
/ 08 июня 2010

Я удивлен, что никто не упомянул подсказку о блокировке WITH (UPDLOCK). Это очень полезно, если у вас есть тупики, например, с две пары выбора-вставки, работающие параллельно.

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

13 голосов
/ 19 марта 2009

Однажды я добавил в закладки хорошую статью о Расширенная блокировка SQL Server на SQL-Server-Performance.com. Эта статья выходит за рамки классической тупиковой ситуации, о которой вы упоминали, и может дать вам некоторое представление о вашей проблеме.

5 голосов
/ 18 июня 2010

Я полагаю, что оператор select получает блокировку чтения, когда вы приходите с оператором update, тогда ему необходимо перейти на блокировку записи.

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

Если вы используете функцию выбора для обновления (UPDLOCK), тогда с самого начала будет установлена ​​блокировка записи, и тогда у вас не возникнет проблема взаимоблокировки.

5 голосов
/ 19 марта 2009

Блокировки между отдельными запросами могут происходить, поскольку они блокируют отдельные строки, а не всю таблицу:

Запрос на обновление получает блокировку обновления для нескольких строк в таблице, а запрос на выборку получает блокировку чтения для некоторых других строк в таблице. Затем запрос на обновление пытается получить блокировку обновления для строк, которые заблокированы для чтения, и запрос на выборку пытается получить блокировку чтения для строк, которые заблокированы для обновления.

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

1 голос
/ 19 марта 2009

Прочтите должным образом об транзакциях и уровнях изоляции: для более плотной, но довольно тщательной и технологически нейтральной работы см. Принципы обработки транзакций . Это потрясло мой мир (и дало мне немало головных болей!).

Я не уверен, с чем у вас проблемы или какой уровень изоляции вы используете. Но учтите следующее: если ядро ​​базы данных знает, что если вы выполняете чтение за одну транзакцию, как оно может определить, собираетесь ли вы выполнять запись позже? Высокие уровни изоляции требуют блокировки при каждом чтении, возможно, по всей таблице для защиты от фантомных чтений, так как данные могут позже повлиять на запись.

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

0 голосов
/ 19 марта 2009

Вы должны прочитать об изоляции транзакций: http://msdn.microsoft.com/en-us/library/ms173763.aspx

...