Является ли NOLOCK (подсказка Sql Server) плохой практикой?

125

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

Итак, с этим массивным заявлением об отказе от ответственности, плохо ли использовать подсказку NOLOCK в каком-либо выражении Sql? Несколько лет назад один из Sql-администраторов предложил мне использовать NOLOCK, если меня устраивает «грязное чтение», которое даст мне немного больше производительности моей системы, потому что каждое чтение не блокирует таблица / строка / независимо.

Мне также сказали, что это отличное решение, если у меня возникают тупиковые ситуации. Итак, я начал следовать этой мысли в течение нескольких лет, пока гуру Sql не помог мне с некоторым случайным кодом и не заметил все NOLOCKS в моем коде sql. Меня вежливо отругали, и он попытался объяснить мне это (почему это нехорошо), и я вроде как потерялся. Я чувствовал, что суть его объяснения заключалась в том, что «это пластырь для решения более серьезной проблемы ... особенно если вы зашли в тупик. Таким образом, устраните корень проблемы ».

Я недавно погуглил об этом и наткнулся на этот пост .

Итак, могут ли некоторые гуру-сенсеи sql db просветить меня, пожалуйста?

Pure.Krome
источник
Я не понимаю, Сэм, ты говоришь использовать изоляцию моментальных снимков, если это сайт, на котором много читается. Но тогда вы говорите, что ТАК это сделал, и это плохо? или просто их использование NOLOCK?
Pure.Krome

Ответы:

67

С подсказкой NOLOCK уровень изоляции транзакции для SELECTоператора равен READ UNCOMMITTED. Это означает, что запрос может увидеть грязные и противоречивые данные.

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

Я предлагаю прочитать « Когда помогает изоляция снимков» и «Когда больно» - MSDN рекомендует использовать READ COMMITTED SNAPSHOT, а не SNAPSHOT в большинстве случаев.

OMG Пони
источник
1
Рекс, пожалуйста, не стесняйтесь добавить примечание об изоляции снимков.
Sam Saffron,
2
Да, Сэм говорит об изоляции снимка, а вы предлагаете прочитать зафиксированный снимок. я так запутался: P (и я еще не вникал в статьи!)
Pure.Krome
2
Иногда это полезно, но обычно не для продакшена. Я часто использую его для получения выборки данных для тестирования или для создания отчетов, где меня больше всего волнует приблизительный порядок величины, когда грязное чтение не имеет значения.
TimothyAWiseman
NOLOCK == меня не волнует, пропущены ли зафиксированные строки, включены ли незавершенные строки, в редких случаях одна и та же строка возвращается более одного раза, а в очень редких случаях возвращаются строки, которые не соответствуют моему запросу. (см. blogs.msdn.com/b/sqlcat/archive/2007/02/01/… , найдено из другого SO q'n по этой теме)
Эндрю Хилл
106

До работы на переполнение стека, я был против NOLOCKпо принципу , что вы могли бы потенциально выполнить SELECTс NOLOCKи получить обратно результаты с данными , которые могут быть устаревшими или противоречивыми. Следует задуматься над тем, сколько записей может быть вставлено / обновлено одновременно, когда другой процесс может выбирать данные из той же таблицы. Если это происходит часто, то высока вероятность взаимоблокировок, если вы не используете режим базы данных, такой как READ COMMITED SNAPSHOT.

С тех пор я изменил свой взгляд на использование, NOLOCKувидев, как он может улучшить SELECTпроизводительность, а также устранить взаимоблокировки на сильно загруженном SQL Server. Бывают случаи, когда вам может быть все равно, что ваши данные не на 100% зафиксированы, и вам нужно быстро вернуть результаты, даже если они могут быть устаревшими.

Задайте себе вопрос, когда думаете об использовании NOLOCK:

Включает ли мой запрос таблицу с большим количеством команд INSERT/, и UPDATEбеспокоюсь ли я, могут ли данные, возвращенные из запроса, не содержать этих изменений в данный момент?

Если ответ отрицательный, используйте NOLOCKдля повышения производительности.


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

Джефф Далгас
источник
7
ИМО, это немного упрощенно. Тупиковые ситуации можно устранить, используя закрывающие индексы, снимая нагрузку с кластерного индекса.
Митч Уит,
8
Я не хочу преуменьшать важность хорошего индексного покрытия. Бывают случаи, что запросы, использующие NOLOCK, могут добавить дополнительную производительность помимо выигрыша, достигаемого за счет индексов в таблицах с большим количеством вставок / обновлений. Скорость запросов в Stack Overflow имеет первостепенное значение даже за счет неточных или отсутствующих данных.
Джефф Далгас
9
По-видимому, можно получить повторяющиеся строки, используя NOLOCK. Это означает, что я должен проголосовать против вашего ответа. Сожалею.
ErikE 07
1
@MitchWheat A SELECT, чтение только из покрывающего индекса, может вызвать тупик. SPID 1) начать SELECTс индекса покрытия. SPID 2) Запустить UPDATEтаблицу. Затем Update переходит к обновлению индекса покрытия. UPDATEдостигает диапазона индекса, заблокированного, SELECTи становится заблокированным. SPID 1), продолжая поиск по покрывающему индексу, находит диапазон, заблокированный с помощью, UPDATEи становится заблокированным. ЗАМОК . Ничто не может разрешить этот тупик (кроме обнаружения ошибки SQL Server 1205 и автоматического повторения или использования NOLOCK)
Ян Бойд
2
Я думаю, что важно отметить в этом ответе то, что он подходит для рассматриваемой проблемы . В зависимости от вашего приложения риск устаревших / незафиксированных / повторяющихся / отсутствующих данных может не стоить компромисса.
Holistic Developer
20

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

НО , имейте в виду, что большинство проблем с блокировкой связано с отсутствием «правильных» индексов для вашей рабочей нагрузки запросов (при условии, что оборудование подходит для этой задачи).

И объяснение гуру было правильным. Обычно это пластырь для решения более серьезной проблемы.

Изменить : я определенно не предлагаю использовать NOLOCK. Думаю, мне следовало это ясно дать понять. (Я бы использовал его только в экстремальных обстоятельствах, когда я проанализировал, что это нормально). В качестве примера, некоторое время назад я работал над некоторым TSQL, в который был добавлен NOLOCK, чтобы попытаться облегчить проблемы с блокировкой. Я удалил их все, установил правильные индексы, и ВСЕ взаимоблокировки исчезли.

Митч Уит
источник
3
Хм .. Я все еще не понимаю. Так что это нормально, но это тоже плохая форма ... это то, что вы говорите?
Pure.Krome
Если исходить из того, что вы НИКОГДА не заботитесь о грязном чтении, это не повредит. НО, как правило, это лечение симптома, а не причины ...
Митч Уит,
2
Ну, я не думаю, что его справедливый rexem был просто отвергнут, я думаю, вы не исправили произвольные ошибки, которые просто всплывают, когда вы используете nolock. Нехорошо получать время от времени на вашем веб-сайте пустую страницу с ошибкой, это действительно плохая форма. Мне не нравится утверждение, что «если вас не волнуют грязные чтения, все в порядке» ... это не нормально, даже если вас не волнуют грязные чтения
Сэм Саффрон
Пустая страница, которую вы получаете, когда запрос генерирует исключение, для которого вы не реализовали логику повтора. Что происходит на ваших сайтах, когда выполняется запрос результатов с исключением, везде ли у вас есть логика повтора?
Сэм Саффрон,
Возьмем очень хорошо оптимизированный запрос, который, как вы знаете, попадает в правильные индексы. Затем добавьте подсказки nolock и смотрите, как это становится быстрее. Если вас не беспокоят грязные чтения, вы никогда не пострадаете, используя nolock.
Hardwareguy,
13

Сомневаюсь, что это был «гуру», имевший хоть какой-то опыт работы в условиях высокой посещаемости ...

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

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

С другой стороны, если у вас есть расширенный поиск продуктов для веб-сайта (то есть что-то, что, вероятно, не будет кэшироваться и будет немного интенсивным), и вы когда-либо создавали сайт с более чем несколькими одновременными пользователями (феноменальное количество «эксперты» этого не сделали), смешно ограничивать все остальные процессы, стоящие за этим.

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

РЕДАКТИРОВАТЬ: Это помогает не только с тупиками, но и с тем, насколько вы собираетесь заставить всех ждать, пока вы не закончите, или наоборот.

Используете NOLOCK Hint в EF4?

Gats
источник
10

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

  • При запросе отдельных значений / строк всегда использовать NOLOCK - плохая практика - вы, вероятно, никогда не захотите отображать неверную информацию или, возможно, даже предпринять какие-либо действия с неверными данными.
  • При отображении приблизительной статистической информации NOLOCK может быть очень полезным. Возьмем, к примеру, SO: было бы бессмысленно брать блокировки для чтения точного количества просмотров вопроса или точного количества вопросов для тега. Никого не волнует, если вы сейчас неправильно зададите 3360 вопросов с тегом «sql-server», а из-за отката транзакции - 3359 вопросов через секунду.
realMarkusSchmidt
источник
Я совершенно не согласен с вашим первым пунктом. ЕСЛИ вы запрашиваете отдельные значения / строки, и вы указываете уникальный идентификатор для этой строки, и вы знаете, что никакой другой процесс не будет получать к ней доступ, тогда использование nolock вполне приемлемо и снижает блокировку в параллельном приложении.
tuseau
1
Нет, это не так. Строка может измениться по другим причинам, например, при вставке другой строки страница разделяется. Правильная индексация, чтение зафиксированного снимка и изоляция снимка - почти всегда лучшие идеи.
Марк Совул
1
@tuseau, если вы «знаете», что ни один другой процесс не будет обращаться к строке, действие блокировки ничего не заблокирует, поэтому вам (практически) ничего не стоит,
Эндрю Хилл
2

Как профессиональный разработчик, я бы сказал, что это зависит от обстоятельств. Но я определенно следую советам GATS и OMG Ponies. Знайте, что вы делаете, знайте, когда это помогает, а когда болит и

читать подсказки и другие плохие идеи

что может помочь Вам глубже понять sql server. Я обычно следую правилу, что подсказки SQL - это ЗЛО, но, к сожалению, я использую их время от времени, когда мне надоело заставлять сервер SQL делать что-то ... Но это редкие случаи.

Люк

Счастливчик Люк
источник
2

Когда служба поддержки приложений хотела отвечать на специальные запросы с производственного сервера с помощью SSMS (которые не обслуживались посредством отчетов), я попросил их использовать nolock. Это не влияет на «основной» бизнес.

richard101
источник
2

Я согласен с некоторыми комментариями о подсказке NOLOCK и особенно с теми, кто говорит «используйте ее, когда это уместно». Если приложение написано плохо и неправильно использует параллелизм - это может вызвать усиление блокировки. Таблицы с высокой степенью транзакций также все время блокируются из-за своей природы. Хорошее покрытие индекса не поможет при извлечении данных, а вот установка ISOLATION LEVEL на READ UNCOMMITTED помогает. Также я считаю, что использование подсказки NOLOCK безопасно во многих случаях, когда характер изменений предсказуем. Например - на производстве, когда задания с путешественниками проходят через разные процессы с большим количеством вставок измерений, вы можете безопасно выполнить запрос к завершенному заданию с подсказкой NOLOCK и таким образом избежать конфликтов с другими сеансами, которые помещают в таблицу ПРОДВИЖЕННЫЕ или ЭКСКЛЮЗИВНЫЕ блокировки. / стр. Данные, к которым вы обращаетесь в этом случае, являются статическими, но они могут находиться в очень транзакционной таблице с сотнями миллионов записей и тысячами обновлений / вставок в минуту. ура

user2041151
источник
2

Я считаю, что использовать nolock практически никогда нельзя.

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

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

NOLOCK - это суррогатный тег для «меня не волнует, содержит ли этот ответ повторяющиеся строки, строки, которые были удалены, или строки, которые не были вставлены с самого начала из-за отката»

Ошибки, которые возможны при NOLOCK:

  • Строки, которые совпадают, не возвращаются.
  • отдельные строки возвращаются несколько раз (включая несколько экземпляров одного и того же первичного ключа)
  • Возвращаются несоответствующие строки.

Любое действие, которое может вызвать разделение страницы во время выполнения выбора noLock, может вызвать эти вещи. Практически любое действие (даже удаление) может вызвать разделение страницы.

Следовательно: если вы «знаете», что строка не будет изменена во время работы, не используйте nolock, так как индекс обеспечит эффективное извлечение.

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

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

Эндрю Хилл
источник
2

По возможности, лучшие решения:

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

Уровень изоляции транзакции SNAPSHOT был создан, потому что MS теряла продажи Oracle. Oracle использует журналы отмены / повтора, чтобы избежать этой проблемы. Postgres использует MVCC. В будущем Heckaton от MS будет использовать MVCC, но это уже годы, когда он будет готов к производству.

PWY
источник
Выше опечатка. Я хочу сказать «лучший фундаментальный механизм изоляции транзакций».
pwy 07
1
Уровень изоляции транзакций SNAPSHOT - изобретение MS. Обычно он помещает данные во временную таблицу в TEMPDB. Эта БД используется всеми БД на коробке. Итак, вы захотите использовать SSD для TEMPDB, когда это возможно. Вероятно, это меньше усилий, чем другие варианты.
pwy 07
1

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

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

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

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

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

Чудотворец
источник
-2

В реальной жизни, когда вы сталкиваетесь с уже написанными системами и добавляющими индексы в таблицы, а затем резко замедляете загрузку данных 14-гигабайтной таблицы данных, вы иногда вынуждены использовать WITH NOLOCK в своих отчетах и ​​обработку в конце месяца, так что совокупные функции (сумма , count и т. д.) не блокируют строки, страницы, таблицы и снижают общую производительность. Легко сказать, что в новой системе никогда не используйте WITH NOLOCK и не используйте индексы, но добавление индексов резко снижает загрузку данных, и когда мне тогда говорят, ну, ну, измените базу кода, чтобы удалить индексы, затем массовую загрузку, а затем воссоздать индексы - что все хорошо, если вы разрабатываете новую систему. Но не тогда, когда у вас уже есть система.

user6699628
источник
1
о чем ты говоришь
Макс Александр Ханна