В NOLOCK или НЕ в NOLOCK, вот в чем вопрос - PullRequest
14 голосов
/ 03 января 2011

Это действительно больше обсуждение, чем конкретный вопрос о nolock.

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

Это просто огромный спад с SQL-сервером? Является ли это просто ошибкой в ​​дизайне БД (у меня не 3-й уровень, а его закрытие) Кто-нибудь там запускает приложение SQL-сервера без nolocks? Это проблемы, которые Oracle лучше обрабатывает с большим количеством грандиозных блокировок записей.

Разве SQL-сервер просто не способен обрабатывать большие нагрузки? Есть ли лучший выход из ситуации, чем чтение незафиксированных данных? Я хотел бы услышать, что думают люди.

Спасибо

Ответы [ 5 ]

13 голосов
/ 03 января 2011

SQL Server добавил snapshot isolation в SQL Server 2005, это позволит вам по-прежнему читать последнее правильное значение, не дожидаясь блокировок. StackOverflow также использует изоляцию моментальных снимков. Уровень изоляции моментальных снимков более или менее совпадает с тем, который использует Oracle, поэтому взаимоблокировки не часто встречаются в Oracle. Просто имейте в виду, что у вас достаточно места в базе данных tempdb, если вы включите его

из Книги Он-лайн

Когда READ_COMMITTED_SNAPSHOT опция базы данных включена, читать совершенная изоляция использует строку управление версиями для обеспечения уровня выписки прочитайте последовательность. Операции чтения требуются только блокировки уровня таблицы SCH-S и нет блокировки страницы или строки. Когда READ_COMMITTED_SNAPSHOT база данных опция выключена, которая является настройка по умолчанию, чтение зафиксировано изоляция ведет себя так, как это было раньше версии SQL Server. И то и другое реализации соответствуют ANSI определение прочитанного совершено изоляция.

11 голосов
/ 03 января 2011

Если кто-то скажет, что без NOLOCK его приложение всегда будет заблокировано, то (скорее всего) возникнет проблема с его запросами. взаимоблокировка означает, что две транзакции не могут быть выполнены из-за конфликта ресурсов и проблема не может быть решена.Пример:

Рассмотрим транзакции A и B. Оба находятся в полете.Транзакция A вставила строку в таблицу X, а транзакция B вставила строку в таблицу Y, поэтому транзакция A имеет эксклюзивную блокировку X, а транзакция B - эксклюзивную блокировку Y.

Теперь, транзакция A нуждаетсявыполнить SELECT для таблицы Y, а транзакция B должна выполнить SELECT для таблицы X.

Две транзакции заблокированы: A требуется ресурс Y, а B нужен ресурс X. Поскольку ни одна транзакция не может продолжаться, пока другая не завершится,Ситуация не может быть решена: ни одна транзакция не требует удовлетворения для ресурса, пока другая транзакция не снимет свою блокировку с ресурса в конфликте (либо ROLLBACK, либо COMMIT, не имеет значения.)

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

В реальной жизни взаимоблокировки редки (IMHO).Один исправляет их с помощью

  • , гарантируя, что область транзакции настолько мала, насколько это возможно, что делает SQL-сервер автоматически (область транзакции SQL Server по умолчанию представляет собой один оператор с неявным COMMIT), и
  • обеспечение доступа транзакций к ресурсам в одинаковой последовательности.В приведенном выше примере, если транзакции A и B заблокировали ресурсы X и Y в одной и той же последовательности, тупиковая ситуация не возникнет.

Таймауты

Тайм-аут, с другой стороны, возникает, когда транзакция превышает время ожидания и откатывается из-за конфликта ресурсов.Например, Транзакции A необходим ресурс X. Ресурс X заблокирован Транзакцией B, поэтому Транзакция A ожидает снятия блокировки.Если блокировка не снята в течение срока ожидания запросов, ожидающая транзакция отменяется и откатывается.С каждым запросом связан тайм-аут запроса (по-моему, значение по умолчанию - 30 с), после которого транзакция прерывается и откатывается.Тайм-аут запроса может быть установлен равным 0 с, и в этом случае SQL Server будет ждать запрос вечно.

Это, вероятно, то, о чем они говорят.По моему опыту, такие таймауты обычно происходят в больших базах данных, когда большие пакетные задания обновляют тысячи и тысячи записей в одной транзакции, хотя они могут происходить из-за того, что транзакция выполняется слишком долго (подключитесь к вашей производственной базе данных в Query Abalyzer, выполните BEGINTRANSACTION, обновите одну строку в часто используемой таблице в Query Analyzer и перейдите на ланч, не выполняя ROLLBACK или COMMIT TRANSACTION, и посмотрите, сколько времени понадобится рабочим администраторам баз данных для вас. Не спрашивайте меня, как язнайте это)

Этот тайм-аут обычно приводит к тому, что разбрызгивание совершенно невинного SQL со всеми видами подсказок NOLOCK

[ СОВЕТ: если вы собираетесь это сделать,просто выполните команду SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED в качестве первого оператора в вашей хранимой процедуре и покончили с ним.]

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

Мое общее правило заключается в том, что следует избегать использования табличных подсказок, насколько это возможно.Пусть SQL Server и его оптимизатор запросов выполняют свою работу.

Правильный способ избежать такого рода проблем - избежать таких транзакций (например, вставить миллион строк одним махом), которые вызывают проблемы. Стратегия блокировки, заложенная в реляционную базу данных SQL, разработана для небольших транзакций с коротким объемом. Замок должен быть небольшим по объему и коротким по продолжительности. Подумайте: «Банковский кассир обновляет чей-то текущий счет с помощью депозита». в качестве основного варианта использования. Спроектируйте свои процессы так, чтобы они работали в этой модели, и вы всегда будете намного счастливее.

Вместо вставки миллиона строк в одном операторе mondo insert выполняйте работу в независимых чанках и фиксируйте каждый чанк независимо. Если ваша миллионная вставка строки умирает после обработки 999 000 строк, вся выполненная работа теряется (не говоря уже о том, что откат может быть почти равен *, и таблица все еще заблокирована во время отката). Если вы вставите миллион строк в блок из 1000 строк каждая, фиксируясь после каждого блока, вы избегаете конфликта блокировок, который вызывает взаимные блокировки, так как блокировки будут получены и сняты, и все будет продолжать двигаться. Если что-то идет на юг в 999-м блоке из 1000 строк, и транзакция прерывается и откатывается, вы все равно вставили 998 000 строк; вы потеряли только 1000 строк работы. Перезапустить / Повторить намного проще.

Кроме того, повышение блокировки происходит в больших транзакциях. Для эффективности блокировки увеличиваются в размерах с увеличением количества блокировок, удерживаемых транзакцией. Если одна транзакция вставляет / обновляет / удаляет одну строку в таблице, я получаю блокировку строки. Продолжайте делать это, и как только число блокировок строк, удерживаемых этой транзакцией для этой таблицы, достигнет порогового значения, SQL Server расширит стратегию блокировок: блокировки строк будут объединены и преобразованы в блокировку страниц меньшего числа, что увеличит объем замки держались. С этого момента вставка / удаление / обновление одной строки заблокирует эту страницу в таблице. Как только количество удерживаемых блокировок страниц достигает порогового значения, блокировки страниц снова консолидируются, и стратегия блокировок перерастает в блокировки таблиц: транзакция теперь блокирует всю таблицу, и никто больше не может играть до тех пор, пока транзакция не завершится или не откатится.

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

Сам я стараюсь максимально избегать его использования.

Надеюсь, это поможет.

4 голосов
/ 03 января 2011

Нет, нет необходимости использовать NOLOCK. Ссылки: SO 1

Что касается нагрузки, мы имеем дело с 2000 строк в секунду, что является небольшим изменением по сравнению с 35k TPS

Взаимные блокировки вызваны конфликтом блокировок и обычно вызваны несогласованным порядком записи в таблицы в транзакциях. ОРМ особенно мусор в этом. Мы получаем их очень редко. Хорошо написанный DAL должен повторить попытку также в соответствии с MSDN.

2 голосов
/ 03 января 2011

В традиционной нормализованной среде OLTP NOLOCK является запахом кода и почти наверняка не нужен в правильно спроектированной системе.

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

1 голос
/ 25 сентября 2012

Вы должны использовать nolock только на неизменном столе.Конечно, это будет то же самое, что и Read Committed Snapshot.Без моментального снимка вы экономите только время, необходимое для применения общей блокировки, а затем для ее удаления, что в большинстве случаев не требуется.

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

Конечно, может быть разумным получить грубые оценки или просто проверить процесс.1007 *

Основное правило - если вы заботитесь о данных вообще, а данные меняются, не используйте NoLOCK.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...