Skip to content

Используете NOLOCK? Так вот вы и получаете неверные результаты запроса

Пересказ статьи Brent Ozar. Using NOLOCK Here’s How You’ll Get the Wrong Query Results.


Волшебный WITH(NOLOCK) в вашем запросе, похоже, заставляет его выполняться быстрее. А как насчет недостатков? Давайте разберемся.
Мы начнем со свободно распространяемой публичной базы данных StackOverflow.com - подойдет любая, даже 10GB mini - и выполним этот запрос:
UPDATE dbo.Users
SET WebsiteUrl = 'https://www.BrentOzar.com/';

Мы просто меняем веб-страницу каждого пользователя на нашу. Затем в отдельном окне, пока выполняется это обновление, выполним:
SELECT COUNT(*) FROM dbo.Users WITH (NOLOCK);
GO 20

Результаты? Картинка полезней тысячи слов:


WITH (NOLOCK, НЕТ_ТОЧНОСТИ)

Конечно, мы запустили обновление на таблице Users, но мы точно не меняем количество пользователей в базе данных. Однако из-за специфики работы NOLOCK мы получаем различное число пользователей всякий раз, когда мы запускаем запрос на выполнение!

Это...это не хорошо. Но это именно так, как задумано. Когда вы используете грязное чтение, также известное как уровень изоляции READ UNCOMMITTED, ваш запрос может давать неверные результаты, в числе которых:

  1. Вы можете видеть строки дважды.

  2. Вы можете вообще пропустить строки.

  3. Вы можете видеть данные, которые не будут зафиксированы.

  4. Ваш запрос может отказать с ошибкой: "невозможно продолжить сканирование без блокировки из-за перемещения данных".


К счастью, это довольно легко пофиксить:

  • Создайте индекс на таблице (любой одностолбцовый индекс будет прекрасно работать в данном конкретном примере, предоставляя SQL Server сокращенную копию таблицы для сканирования).

  • Используйте более подходящий уровень изоляции - скажем, Read Committed Snapshot Isolation.

  • Уберите хинт NOLOCK из запроса - хотя это может закончиться блокировкой, так что вам придется прибегнуть к настройке индексов и запросов.

Trackbacks

No Trackbacks

Comments

Display comments as Linear | Threaded

No comments

The author does not allow comments to this entry

Add Comment

Enclosing asterisks marks text as bold (*word*), underscore are made via _word_.
Standard emoticons like :-) and ;-) are converted to images.

To prevent automated Bots from commentspamming, please enter the string you see in the image below in the appropriate input box. Your comment will only be submitted if the strings match. Please ensure that your browser supports and accepts cookies, or your comment cannot be verified correctly.
CAPTCHA

Form options

Submitted comments will be subject to moderation before being displayed.