Я никогда не видел в 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 и получайте ту точность, которую ожидают ваши пользователи.
Комментариев нет:
Отправить комментарий