Для NOLOCK или NOT NOLOCK это вопрос

Это скорее дискуссия, чем конкретный вопрос о nolock.

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

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

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

Спасибо

Ответы

Ответ 1

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

из книги On Line

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

Ответ 2

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

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

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

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

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

Тупики редки в реальной жизни (ИМХО). Один выпрямляет их

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

Таймауты

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

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

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

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

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

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

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

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

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

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

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

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

Ответ 3

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

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

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

Ответ 4

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

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

Ответ 5

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

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

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

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