Использование IsolationLevel.Snapshot, но БД все еще блокируется

Я являюсь частью команды, создающей веб-сайт на базе ADO.NET. Иногда у нас есть несколько разработчиков и инструмент автоматического тестирования, работающий одновременно с копией базы данных для разработки.

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

Чтобы использовать уровень изоляции моментальных снимков, мы используем:

ALTER DATABASE <database name>
SET ALLOW_SNAPSHOT_ISOLATION ON;

и в С#:

Transaction = SqlConnection.BeginTransaction(IsolationLevel.Snapshot);

Обратите внимание, что моментальный снимок IsolationLevel отличается от моментального снимка ReadCommitted, который мы также пробовали, но в настоящее время не используем.

Когда один из разработчиков входит в режим отладки и приостанавливает работу приложения .NET, он будет удерживать соединение с активной транзакцией во время отладки. Теперь я ожидаю, что это не будет проблемой - в конце концов, все транзакции используют уровень изоляции моментальных снимков, поэтому, пока одна транзакция приостановлена, другие транзакции должны иметь возможность нормально работать, поскольку приостановленная транзакция не удерживает никаких блокировок. Конечно, когда приостановленная транзакция завершится, скорее всего, будет обнаружен конфликт; но это приемлемо, пока другие разработчики и автоматизированные тесты могут работать беспрепятственно.

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

Кто-нибудь знает, почему это происходит и/или как я могу добиться настоящего оптимистичного (неблокирующего) параллелизма?

Решение (неудачное для меня): Remus Rusanu заметил, что писатели всегда блокируют других писателей; это поддерживается MSDN - он не совсем говорит об этом, а только упоминает, что нужно избегать блокировок чтения-записи. Короче говоря, поведение, которое я хочу, не реализовано в SQL Server.


person Eamon Nerbonne    schedule 25.06.2009    source источник


Ответы (2)


Уровень изоляции SNAPSHOT влияет, как и все уровни изоляции, только на чтение. Записи по-прежнему блокируют друг друга. Если вы считаете, что видите блокировку чтения, вам следует продолжить расследование и проверить типы и имена ресурсов, на которых происходит блокировка (wait_type и wait_resource в sys.dm_exec_requests).

Я бы не советовал вносить изменения в код для поддержки сценария, в котором разработчики минутами смотрят на отладчик. Если вы считаете, что этот сценарий может повториться в продакшене (т.е. клиент зависнет), то это совсем другая история. Чтобы достичь того, чего вы хотите, вы должны свести к минимуму записи и выполнять все записи в конце транзакции, в одном единственном вызове, который фиксируется перед возвратом. Таким образом, ни один клиент не может удерживать X-блокировки в течение длительного времени (не может зависать, удерживая X-блокировки). На практике это довольно сложно реализовать и требует от разработчиков большой дисциплины в том, как они пишут код доступа к данным.

person Remus Rusanu    schedule 25.06.2009
comment
Такое поведение маловероятно в производстве. С другой стороны, версия для разработки очень важна, и я был бы готов внести изменения в код, если это упростит разработку. К сожалению, стиль блокировки в стиле svn (надеяться на лучшее и просто терпеть неудачу при конфликте), похоже, не реализован. Возможность иметь длительные и сложные транзакции без блокировки всех мелких транзакций все еще была бы полезной — как есть, мы используем меньше транзакций, что идеально, просто чтобы избежать блокировки. - person Eamon Nerbonne; 25.06.2009
comment
Серебряной пули не существует. Но если вы обнаружите, что вас часто блокируют при записи по сравнению с записью, вам следует подумать, почему это происходит, почему разные «запросы» вызывают обновления одних и тех же данных. Возможно, вы сможете лучше разбить свое приложение, снизив вероятность перекрытия. Возможно, некоторые обновления могут быть отложены, поставлены в очередь в рабочей таблице во время пользовательской транзакции (постановка в очередь/изъятие из очереди может быть сделана свободной от блоков, но с осторожностью) и позже обработаны выделенными пакетными процессами. Также убедитесь, что все транзакции блокируют только необходимый минимум (без блокировок страниц/таблиц, без эскалации, без бесполезных сканирований таблиц). - person Remus Rusanu; 25.06.2009

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

Вот шаги:

ALTER DATABASE <databasename>
SET READ_COMMITTED_SNAPSHOT ON;
GO

ALTER DATABASE <database name>
SET ALLOW_SNAPSHOT_ISOLATION ON;
GO

После включения изоляции моментальных снимков для базы данных разработчики и пользователи должны запросить выполнение своих транзакций в этом режиме моментальных снимков. Это необходимо сделать перед запуском транзакции либо с помощью директивы на стороне клиента в объекте транзакции ADO.NET, либо в запросе Transact-SQL с помощью следующего оператора:

SET TRANSACTION ISOLATION LEVEL SNAPSHOT

Радж

person Raj    schedule 25.06.2009
comment
В базе данных включена функция allow_snapshot_isolation. Невыполнение этого требования приводит к немедленному исключению; вы не можете установить уровень изоляции на моментальный снимок, когда параметр allow_snapshot_isolation отключен (т. е. установка уровня изоляции не завершается автоматически). Я обновлю сообщение, чтобы отразить точные необходимые команды, спасибо! - person Eamon Nerbonne; 25.06.2009