Практика SQL Server

NOLOCK: быстрый ответ может быть неверным

Воспроизведите грязное чтение в двух сеансах, разберите оставшиеся блокировки и замените NOLOCK без потери достоверности отчётов.

Отчёт, завершившийся за две секунды, может быть менее полезен, чем отчёт, который ждал пять секунд, если его итог никогда не существовал в подтверждённых данных. NOLOCK меняет допустимое содержимое результата. Для расчёта счетов, управления запасами и оперативных решений это изменение бизнес-смысла, а не просто ускорение прежнего запроса.

Воспроизведение неправильного результата

Возьмите отдельную учебную базу и два окна запросов, подключённых именно к ней. Подготовку выполните один раз. В окне A начните транзакцию и оставьте её открытой. В окне B выполните чтение с NOLOCK, затем вернитесь в A и отмените изменение.

CREATE TABLE dbo.NolockDemo (Id int PRIMARY KEY, Balance int NOT NULL);
INSERT dbo.NolockDemo VALUES (1, 100);
BEGIN TRAN;
UPDATE dbo.NolockDemo SET Balance = 900 WHERE Id = 1;
-- Run the reader in window B, then execute:
-- ROLLBACK;
SELECT Balance FROM dbo.NolockDemo WITH (NOLOCK) WHERE Id = 1;

Окно B может показать 900, хотя такое значение никогда не будет зафиксировано. После отката подтверждённый баланс остаётся равным 100. Обычный запрос при блокировочном READ COMMITTED способен ждать завершения этой транзакции. Если включён READ_COMMITTED_SNAPSHOT, он может прочитать предыдущую подтверждённую версию. Поэтому сначала проверьте параметр базы. Быстрый ответ сам по себе не доказывает необходимость NOLOCK.

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

Поиск причины исходного ожидания

NOLOCK по-прежнему требует блокировок стабильности схемы при компиляции и выполнении. Изменение схемы поэтому может остановить такой запрос. Долгий запрос, в свою очередь, способен задержать изменение схемы. Подсказка также не устраняет вычисления, сбросы сортировки на диск, передачу по сети и чтение файлов. Разбирайте фактический тип ожидания, а не только жалобу на медленный отчёт.

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

Определите требуемую согласованность. Достаточно ли подтверждённого состояния для каждой команды? Должны ли несколько команд видеть один момент времени? Допустим ли явно устаревший срез? READ_COMMITTED_SNAPSHOT обеспечивает согласованность отдельной команды; SNAPSHOT может обеспечить её для транзакции. Читаемая реплика способна отставать от основного узла и не гарантирует автоматически согласованность произвольного многошагового процесса.

Контролируемая замена подсказки

Начните с отчёта, результат которого можно независимо проверить. Уберите NOLOCK в представительной тестовой среде, измерьте время и логические чтения, затем добавьте конкурентную запись. При рассмотрении версионирования оцените объём хранилища версий, долгие чтения и поведение существующих пишущих транзакций. Параметр уровня базы влияет не только на отчёт, с которого началась работа.

Приёмочный тест должен повторить эксперимент с балансом и проверить, что неподтверждённое значение не публикуется. Добавьте транзакцию по нескольким таблицам в той последовательности, которую использует приложение. Проверяйте бизнес-инвариант, например совпадение суммы строк со значением в заголовке счёта. Успешный HTTP-ответ отчётного сервиса такой проверки не заменяет.

Отдельно сохраните результаты измерения скорости и корректности. Успешная замена даёт приемлемое подтверждённое состояние при конкурентной нагрузке и укладывается в срок формирования отчёта. Обязательно завершите учебную транзакцию командой ROLLBACK, после чего удалите таблицу упражнения. Для финансового отчёта дополнительно сравните число строк и итоговые суммы на неизменяемой контрольной выборке. Это помогает отличить исправленную согласованность от случайного совпадения результатов одного запуска. NOLOCK должен оставаться осознанным допущением для конкретного сценария, а не невидимым стандартом каждого запроса.

Техническая документация: Microsoft Learn: Table hints · Microsoft Learn: Transaction isolation.

Вопрос по статье

Есть вопрос по этой теме?

Расскажите, что вы оцениваете или с какой проблемой столкнулись. Мы ответим с практической рекомендацией.

Inquiries are not enabled in this preview.

Задать вопрос по этой статье