Я когда-то отметил хорошую статью приблизительно Усовершенствованный SQL Server, блокирующий по SQL-Server-Performance.com. Та статья идет вне классической ситуации с мертвой блокировкой, что Вы упомянули и могли бы дать Вам некоторое понимание Вашей проблемы.
Читайте правильно на транзакциях и уровнях изоляции: для несколько плотного, но довольно полного и технологии нейтральная работа, см. Принципы Обработки транзакций . Это качало мой мир (и дал мне довольно много головных болей!).
я не уверен, что Вы испытываете затруднения из-за, или какой уровень изоляции Вы используете. Но рассмотрите это: поскольку весь механизм базы данных знает, если Вы делаете чтения в одной транзакции, как это может сказать, собираетесь ли Вы сделать запись позже? Высокие уровни изоляции требуют блокировки каждый раз, когда чтение сделано, возможно на всей таблице для защиты от фантомных чтений, так как данные могут влиять на запись позже.
Вы хотели бы, чтобы база данных ожидала, произвольно жаждут монопольной блокировки на Ваших данных? Смотрите на свои уровни изоляции повсюду, и выполняете ли Вы излишне ряд чтений как изолированная транзакция. Не всегда легко определить, как грязные чтения можно терпеть, хотя...
Необходимо читать на изоляции транзакции: http://msdn.microsoft.com/en-us/library/ms173763.aspx
Блокировки между едиными запросами могут произойти, поскольку они блокируют единственные строки, не всю таблицу:
запрос на обновление получает блокировку обновления на нескольких строках в таблице, и запрос Select добирается, чтение соединяют некоторые другие строки в таблице. Запрос на обновление тогда пытается получить блокировку обновления на строках, которые читаются заблокированные, и запрос Select пытается добраться, чтение соединяют строки, которые являются заблокированным обновлением.
Это может стать еще более сложным с блокировками escalading, т.е. база данных решает, что существует слишком много единственных строк, заблокированных транзакцией так, чтобы это было наращено в блокировку раздела таблицы или всей таблицы. Это означает, что блокировка может влиять на строки, которые непосредственно не вовлечены в запрос.
Это может произойти, потому что выбор берет блокировку на двух различных индексах, между тем обновление берет блокировку на тех же индексах в противоположном порядке. Выбору нужны два индекса, потому что первый индекс не покрывает все столбцы, к которым он должен получить доступ; для обновления нужны два индекса, потому что при обновлении столбца ключа индекса, необходимо взять блокировку на нем.
http://blogs.msdn.com/bartd/archive/2006/09/25/770928.aspx имеет фантастическое объяснение. Предложенные исправления включают добавление индекса, который покрывает все столбцы избранные потребности, переключаясь для создания снимков изоляции, или явно вынуждая выбор захватить блокировку обновления, в которой это обычно не нуждалось бы.
Я удивлен, что никто не упомянул подсказку блокировки WITH (UPDLOCK)
. Она очень полезна, если у вас возникают тупики, например, при параллельном выполнении двух пар select-insert.
В SQL Server, если вы выдаете селекты с WITH (UPDLOCK)
, второй селект будет ждать завершения первого селекта. В противном случае они получают общие блокировки, и когда они одновременно пытаются перейти на эксклюзивные блокировки, они заходят в тупик.
Я предполагаю, что оператор select требует блокировки чтения, когда вы идете с оператором update, его необходимо обновить до блокировки записи.
Обновление до блокировки записи требует, чтобы все другие блокировки чтения были сняты (их транзакции выбора завершаются). Но если другому процессу уже пришла в голову блестящая идея перейти на блокировку записи, тогда у вас внезапно появятся два процесса, ожидающих друг друга, чтобы снять блокировку чтения, чтобы они могли получить блокировку записи.
Если используется выборка для обновления (UPDLOCK), тогда с самого начала будет установлена блокировка записи, и тогда у вас не будет проблемы с взаимоблокировкой.