Что такое "с (nolock)" в SQL Server?

Может кто-нибудь объяснить последствия использования with (nolock) на запросы, когда вы должны / не должны использовать его?

Например, если у вас есть банковское приложение с высокой скоростью транзакций и большим количеством данных в определенных таблицах, в каких типах запросов все будет нормально? Есть ли случаи, когда вы всегда должны использовать его / никогда не использовать?

16 ответов

Решение

WITH (NOLOCK) является эквивалентом использования READ UNCOMMITED в качестве уровня изоляции транзакции. Таким образом, вы рискуете прочитать незафиксированную строку, которая впоследствии откатывается, то есть данные, которые никогда не попадали в базу данных. Таким образом, хотя он может предотвратить блокировку чтения другими операциями, он сопряжен с риском. В банковском приложении с высокой скоростью транзакций это, вероятно, не будет правильным решением для любой проблемы, которую вы пытаетесь решить с его помощью, IMHO.

Вопрос в том, что хуже:

  • тупик или
  • неправильное значение?

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

В финансовой базе данных вы используете бизнес-операции. Это означает добавление одной строки к каждой учетной записи. Крайне важно, чтобы эти транзакции были завершены и строки были успешно записаны.

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

Тем не менее, SQL Server 2005 исправил большинство ошибок, которые сделали NOLOCK необходимо. Поэтому, если вы не используете SQL Server 2000 или более раннюю версию, вам это не нужно.

Дальнейшее чтение
Управление версиями на уровне строк

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

Проверьте статью Ицик Бен-Ган. Вот выдержка:

"С подсказкой NOLOCK (или установив уровень изоляции сеанса READ UNCOMMITTED) вы сообщаете SQL Server, что не ожидаете согласованности, поэтому никаких гарантий нет. Имейте в виду, что" противоречивые данные "не только означают, что вы можете увидеть незафиксированные изменения, которые впоследствии были откатаны, или изменения данных в промежуточном состоянии транзакции. Это также означает, что в простом запросе, который сканирует все данные таблицы / индекса, SQL Server может потерять позицию сканирования или может закончиться получая один и тот же ряд дважды. "

Пример учебника для законного использования подсказки nolock - выборка отчета по базе данных OLTP с высоким обновлением.

Взять актуальный пример. Если крупный крупный банк США хотел запустить почасовой отчет в поисках первых признаков запуска уровня города в банке, запрос nolock мог бы отсканировать таблицы транзакций, суммирующие депозиты и снятие наличных по городам. Для такого отчета небольшой процент ошибок, вызванных откатом транзакций обновления, не уменьшит значение отчета.

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

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

Без блокировки не только возвращает неправильные значения, он возвращает фантомные записи и дубликаты.

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

Справедливости ради, вот два специальных сценария, где подсказка Nolock может обеспечить полезность

1) База данных SQL Server до 2005 года, которая должна выполнять длинный запрос к действующей базе данных OLTP, это может быть единственным способом

2) Плохо написанное приложение, которое блокирует записи и возвращает управление пользовательскому интерфейсу, а читатели блокируются на неопределенный срок. Nolock может быть полезен в этом случае, если приложение не может быть исправлено (стороннее и т. Д.), А база данных - до 2005 года, или невозможно включить управление версиями.

Вы можете использовать его, когда вы только читаете данные, и вам неважно, возвращаете ли вы данные, которые еще не зафиксированы.

Это может быть быстрее при операции чтения, но я не могу точно сказать, насколько.

В общем, я рекомендую не использовать его - чтение незафиксированных данных в лучшем случае может быть немного запутанным.

NOLOCK эквивалентно READ UNCOMMITTEDОднако Microsoft говорит, что вы не должны использовать его для UPDATE или же DELETE заявления:

Для операторов UPDATE или DELETE: эта функция будет удалена в следующей версии Microsoft SQL Server. Избегайте использования этой функции в новых разработках и планируйте модифицировать приложения, которые в настоящее время используют эту функцию.

http://msdn.microsoft.com/en-us/library/ms187373.aspx

Эта статья относится к SQL Server 2005, поэтому поддержка NOLOCK существует, если вы используете эту версию. Для того чтобы ваш код был готов к будущему (при условии, что вы решили использовать грязное чтение), вы можете использовать это в своих хранимых процедурах:

SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED

Короткий ответ:

Никогда не используйте WITH (NOLOCK),

Длинный ответ:

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

Результирующий набор может содержать строки, которые еще не были зафиксированы и которые впоследствии часто откатываются.

Ошибка или набор результатов могут быть пустыми, пропустить строки или отображать одну и ту же строку несколько раз.

Это связано с тем, что другие транзакции перемещают данные одновременно с чтением.

READ COMMITTED добавляет дополнительную проблему, когда данные повреждены в одном столбце, когда несколько пользователей одновременно изменяют одну и ту же ячейку.

Есть и другие побочные эффекты, которые приносят в жертву увеличение скорости, которое вы надеялись получить в первую очередь.

Можно утверждать, что это хорошо использовать в местах, где вы можете сойти с рук, но какой в ​​этом смысл? Я не могу придумать ни одной ситуации, когда поврежденные данные приемлемы.

Никогда не используйте NOLOCK никогда.

(Когда-либо)

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

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

Я также расскажу о том, что это, вероятно, не очень хорошая идея в банковском приложении. Или приложение инвентаря. Или где угодно, вы думаете о транзакциях.

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

Это стоит учитывать для любых запросов, используемых для отчетов, особенно если запрос занимает, скажем, более 1 секунды.

Это особенно полезно, если у вас есть отчеты типа OLAP, которые вы используете для базы данных OLTP.

Первый вопрос, который нужно задать: "почему я об этом беспокоюсь?" По моему опыту, фальсификация поведения блокировки по умолчанию часто происходит, когда кто-то находится в режиме "попробуй что-нибудь", и это один из случаев, когда неожиданные последствия не исключены. Слишком часто это случай преждевременной оптимизации и слишком легко может быть встроен в приложение "на всякий случай". Важно понимать, почему вы это делаете, какую проблему это решает и есть ли у вас эта проблема.

Мои 2 цента - имеет смысл использовать WITH (NOLOCK) когда вам нужно создавать отчеты. На этом этапе данные не сильно изменятся, и вы не захотите блокировать эти записи.

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

Для финансовых записей (и почти всех других записей в большинстве приложений) nolock может привести к хаосу, поскольку вы потенциально можете прочитать данные обратно из записи, в которую пишете, и не получить правильные данные.

Я использовал, чтобы получить "следующую партию" для вещей, чтобы сделать. В данном случае не имеет значения, какой именно элемент, и у меня много пользователей, выполняющих этот же запрос.

Используйте nolock, когда вы в порядке с "грязными" данными. Это означает, что nolock может также считывать данные, которые находятся в процессе изменения и / или незафиксированные данные.

Как правило, не рекомендуется использовать его в среде с высокими транзакциями, и поэтому он не является параметром по умолчанию для запроса.

Я использую подсказку (nolock), особенно в базах данных SQLServer 2000 с высокой активностью. Однако я не уверен, что это необходимо в SQL Server 2005. Недавно я добавил эту подсказку в SQL Server 2000 по запросу администратора базы данных клиента, потому что он замечал много блокировок записей SPID.

Все, что я могу сказать, это то, что использование подсказки НЕ повредило нам и, похоже, позволило решить проблему блокировки. Администратор базы данных на этом конкретном клиенте в основном настаивал на том, что мы используем подсказку.

Между прочим, базы данных, с которыми я имею дело, являются бэкэндами к корпоративным системам медицинских заявок, поэтому мы говорим о миллионах записей и более 20 таблиц во многих объединениях. Обычно я добавляю подсказку WITH (nolock) для каждой таблицы в соединении (если только это не производная таблица, в этом случае вы не можете использовать эту конкретную подсказку)

Самый простой ответ - простой вопрос - нужны ли ваши результаты для повторения? Если да, то NOLOCKS не подходит ни при каких обстоятельствах

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

Другие вопросы по тегам