Что такое «с (nolock)» в SQL Server? - PullRequest
560 голосов
/ 26 марта 2009

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

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

Ответы [ 16 ]

421 голосов
/ 26 марта 2009

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

160 голосов
/ 26 марта 2009

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

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

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

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

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

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

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

52 голосов
/ 29 марта 2011

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

Выезд Статья Ицик Бен-Гана . Вот выдержка:

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

52 голосов
/ 26 марта 2009

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

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

30 голосов
/ 03 марта 2010

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

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

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

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

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

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

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

23 голосов
/ 26 марта 2009

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

18 голосов
/ 26 марта 2009

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

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

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

17 голосов
/ 26 марта 2009

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

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

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

14 голосов
/ 26 марта 2009

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

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

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

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

9 голосов
/ 13 июля 2010

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

...