11.9.25

Страсти по SQL Server 2025: ускоренное восстановление базы данных не исправляет проблему NOLOCK!!!

Автор: Brent Ozar, No, Accelerated Database Recovery Doesn’t Fix NOLOCK

Я никогда не видел в T-SQL такой фразы, которую так же любят использовать, как NOLOCK. Мне постоянно кажется, что я написал уже достаточно публикаций об этом, но вот недавно клиент высказал новую идею:

Мы используем Accelerated Database Recovery в SQL Server 2022, который хранит версии строк внутри таблицы. К тому же мы не используем транзакции — наши операции вставки, обновления и удаления выполняются над одной таблицей за раз, а ваши демонстрации всегда используют транзакции, поэтому нас это не затрагивает.

Но это не так работает. Это вообще не так работает. Чтобы показать это, мы настроим SQL Server 2025 и базу данных Stack Overflow с самыми последними возможностями:


USE StackOverflow;
GO
ALTER DATABASE CURRENT 
    SET COMPATIBILITY_LEVEL = 170
GO
ALTER DATABASE CURRENT 
    SET ACCELERATED_DATABASE_RECOVERY = ON;
GO
DropIndexes;
GO
SELECT COUNT(*) 
FROM dbo.Users WITH (NOLOCK)
WHERE DisplayName = N'alex';
GO 20

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


UPDATE dbo.Users
  SET Location = N'NOLOCK City Limits, Nevada'
  WHERE DisplayName <> N'alex';

И количество строк, возвращаемых запросом SELECT, продолжает изменяться. Я не шучу. Когда ваши запросы используют NOLOCK или установку уровня изоляции SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED:

  • Вы можете прочитать одну и ту же строку дважды
  • Вы можете пропустить некоторые строки
  • Вы можете увидеть данные, которые никогда не были зафиксированы
  • Ваш запрос может завершиться ошибкой (could not continue scan with nolock due to data movement)

Если вы думаете, что ваш сценарий каким-то образом магическим образом отличается, ознакомьтесь с другими демонстрациями NOLOCK, прежде чем утверждать обратное.

В случае клиента кто-то на звонке сказал: «В вашей демонстрации удаляются индексы, а у нас индексы есть, поэтому мы в безопасности». Нет, в моей демонстрации индексы удаляются просто для того, чтобы как можно быстрее показать проблему. В зависимости от того, какие именно запросы выполняются, какие изменения данных происходят и какие индексы существуют, вы вполне можете получать случайные результаты.

Другой участник заметил: «Мы никогда не сталкивались с проблемой». Ответ: а вы контролируете точность вывода приложения? Конечно же нет. Вы полагаетесь на то, что пользователи сообщат вам о некорректных данных на экране, но у них нет причин подозревать, что данные неверны. Если в отчете указано, что в прошлом квартале мы продали товаров на сумму 1,234,567 долларов, именно в это пользователь и поверит. Если он запустит отчет снова через пять минут и увидит сумму 1,324,765 долларов, то решит, что кто-то изменил или поправил данные, и посчитает, что второе число верное. Пользователи доверчивы.

Это не значит, что я всегда избегаю NOLOCK! В ситуациях, где мне не нужна абсолютная точность, NOLOCK вполне допустим. Например, вы найдете его во многих скриптах First Responder Kit. Ведь мне не нужна транзакционная точность при отображении количества обращений к вашему индексу.

Но если вашим запросам действительно требуется точность результатов вне зависимости от того, что еще происходит в базе данных, и независимо от того, какие индексы существуют в данный момент, тогда рассмотрите использование Read Committed Snapshot Isolation (RCSI) или Snapshot Isolation (SI). Настройте их, удалите подсказки NOLOCK и получайте ту точность, которую ожидают ваши пользователи.




Комментариев нет:

Отправить комментарий