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

610

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

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

Энди Уайт
источник
Я вложил в вопрос в stackoverflow.com/questions/3836282/… и stackoverflow.com/questions/3836032/… главным образом ответ Джонатана Аллена stackoverflow.com/questions/686724/…
Геннадий Ванин Геннадий Ванин
1
одна ссылка здесь - mssqltips.com/sqlservertip/2470/…
Steam
1
Вот отличная сводка последствий использования NOLOCK blogs.msdn.com/b/davidlean/archive/2009/04/06/…
Брайан

Ответы:

461

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

Дэвид М
источник
156
Большинство банковских приложений могут безопасно использовать nolock, потому что они транзакционные в деловом смысле. Вы только пишете новые строки, вы никогда не обновляете их.
Джонатан Аллен
49
@ Grauenwolf - вставленный, но незафиксированный ряд может привести к грязному чтению.
saasman
16
@ Saasman - Если вы никогда не откатываете транзакции, это не имеет значения. А с таблицей только для вставки вероятность отката невелика. И если они все же произойдут, вы все равно исправите это в отчете о дисперсии на конец дня.
Джонатан Аллен
1
Я укоренился. Я предполагаю, что Добавленные подсказки без блокировки включены. К экзамену:
Росс Буш
11
Если вы используете NOLOCKс, SELECTвы рискуете возвращать одни и те же строки более одного раза (дублированные данные), если данные когда-либо вставляются (или обновляются) в таблицу при выполнении выбора.
Ян Бойд
170

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

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

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

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

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

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

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

Джонатан Аллен
источник
22
Получить баланс аккаунта временно неправильно - не страшно? Что если в этой транзакции вы снимаете наличные в банкомате без ограничения по овердрафту?
Обучение
13
@ Обучение: что произойдет, если вы вытащите деньги за 30 секунд до того, как кто-то снимет вашу карту До тех пор, пока все общение не станет инстинктивным, овердрафты станут фактом жизни.
Джонатан Аллен
6
+1 В финансовом приложении (везде, не только в банках) нет ни обновлений, ни удалений. Даже неправильные операции исправляются путем вставки записей. Что это за термин на английском языке? Это "сторно"? Google не помог мне ответить на этот вопрос
Геннадий Ванин Геннадий Ванин
7
Поздний вход ... тупики должны быть пойманы и повторены. Грязные чтения имеют последствия
gbn
4
@JonathanAllen просто к сведению, термин UTmost, а не UP.
Джимми Д
57

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

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

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

sqlbelle
источник
5
Чуть дальше он объясняет, как получить одну и ту же строку дважды: я воссоздаю таблицу T1 так, чтобы кластерный индекс на col1 был определен как уникальный индекс с опцией IGNORE_DUP_KEY. Это означает, что повторяющиеся значения не могут существовать в столбце col1, а также, что попытка вставить повторяющийся ключ не приведет к сбою транзакции и вызовет ошибку, а просто выдаст предупреждение. Если вы не используете эту странную опцию, вам, вероятно, не придется беспокоиться о получении строк дважды
JanHudecek
Вы все еще можете получить двойные строки даже без опции проводной связи - например, если в вашем запросе используется индекс, который не является уникальным. Это не уникально для nolock.
RMD
54

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

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

saasman
источник
31

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

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

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

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

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

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

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

Эндрю
источник
11
Я согласен с вами, что NOLOCK не должен использоваться для восполнения плохо написанного кода. Тем не менее, я думаю, что ваша атака на Джонатана неоправданна, поскольку он никогда не упоминал транзакции с базой данных . Он просто указывал на то, что финансовые приложения обычно не позволяют вносить изменения в записи (очевидно, есть некоторые исключения). В вашем примере с переводом средств он говорит, что было бы странно, если бы вы изменили значение остатка на счете, а не добавили запись дебета / кредита в своего рода бухгалтерскую книгу.
chrnola
19
Как вы думаете, когда происходит перевод средств с одного счета на другой в разных банках? Какая-то база данных Uber блокирует стол в Bank of America, а другая - в Wells Fargo? Нет. Финансовая транзакция записывается в каждую, а затем процесс на конец дня проверяет, что все записи совпадают.
Джонатан Аллен
24

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

Seibar
источник
21

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

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

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

marc_s
источник
1
было бы неплохо, если бы вы упомянули тот факт, что в SQL Server 2005 есть управление версиями строк, поэтому нолоки больше не нужны.
Джонатан Аллен
Ну, «with (nolock)» все еще имеет место даже в SQL Server 2005 - но преимущества становятся все меньше и меньше, это правда.
marc_s
18

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

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

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

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

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

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

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

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

dkretz
источник
11

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

Используйте только WITH (NOLOCK)в операторе SELECT для таблиц с кластерным индексом.

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

WITH (NOLOCK) часто используется как магический способ ускорить чтение из базы данных.

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

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

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

Чудотворец
источник
2
Чтение незафиксированных данных допустимо, если это не меняет окончательного решения. Например, если вы пытаетесь спрогнозировать, сколько денег ваш розничный магазин заработает в течение следующих 6 месяцев, то, когда Тэмми купила 2 рулона бумажных полотенец, когда она действительно купила 3, не изменится ваше мнение о будущем. ,
Джонатан Аллен
1
Если ваш фильтр включает сейчас, ваши данные будут неточными в момент запуска запроса. Если ваш фильтр включает только исторические данные, использование READ UNCOMITTED не повлияет на него вообще. Есть причина, по которой он был включен в стандарт ANSI.
Джонатан Аллен
2
Никогда не говори никогда. Если вам нужны данные, чтобы быть на 100% точными, то вам не следует использовать nolock. Для меня это обычно не так. При представлении данных пользователю, к тому времени, когда они воздействуют на данные, они, возможно, уже изменились, но, скорее всего, не изменились, и конкуренция за блокировку не стоит задержек с ответом.
Perposterer
Давайте придерживаться систем, достойных существования. Не забывайте, что у Тэмми вполне приличный ум, поэтому использовать базу данных для записи крошечных покупок бумажных полотенец, о которых никто не обращает внимания, в лучшем случае нелепо. Наше внимание сосредоточено на системах, которые действительно важны, например, вовремя платят людям, реагируют на чрезвычайные ситуации и т. Д. Существенным преимуществом является то, что использование WITH (NOLOCK) понимается людьми, программирующими любую систему, достойную существования. Когда человек может выполнять работу лучше, чем база данных, подумайте о том, чтобы использовать эти ресурсы.
WonderWorker
10

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

SoftwareGeek
источник
2
Я думаю, что WITH (NoLOCK) лучше, если вас не волнуют текущие изменения.
Абдул Сабур
9

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

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

Эндрю Хэйр
источник
5
Удивительно, но при работе с финансовыми данными это не проблема. Поскольку строки никогда не редактируются, а учетные записи сверяются в конце дня, чтение временно поддельных данных ничего не делает.
Джонатан Аллен
8

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

Otávio Décio
источник
1
Мы делаем нечто подобное, чтобы представить фоновую задачу с очередью работы. Если, когда он попадает в конкретную запись, он больше не существует / соответствует критериям выбора, он просто переходит к следующей.
TripeHound
7

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

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

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

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

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

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

user52212
источник
1
В SQL Server 2005 добавлено «управление версиями строк», что должно значительно снизить потребность в нуликах. Мы недавно обновились и не обучаем наших администраторов баз данных прекращать их использование.
Джонатан Аллен
5

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

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

Эд Грин
источник