Советы по минимизации блокировки только таблицы добавления в MS SQL Server? - PullRequest
9 голосов
/ 13 июня 2009

Я пишу некоторый код для ведения журнала / аудита, который будет работать в производственной среде (не только при возникновении ошибок или при разработке). После прочтения Coding Horror's опыта мертвой блокировки и регистрации , я решил, что должен обратиться за советом. (Решение Джеффа «не регистрировать» мне не подойдет, это юридически обязательный аудит безопасности)

Существует ли подходящий уровень изоляции для минимизации конфликтов и блокировок? Любые подсказки запроса, которые я могу добавить к оператору вставки или хранимой процедуре?

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

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

Ответы [ 4 ]

5 голосов
/ 14 июня 2009

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

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

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

Шаги для минимизации блокировки:

  • (KEY) выполняет все добавления в таблицу журналов вне основного потока / соединения / транзакции.
  • Убедитесь, что ваша таблица журналов имеет монотонно увеличивающийся кластеризованный индекс (например, int identity), который увеличивается при каждом добавлении сообщения журнала. Это гарантирует, что вставляемые страницы, как правило, находятся в памяти, и позволяет избежать скачков производительности, которые вы получаете с таблицами кучи.
  • Выполнение нескольких операций добавления в журнал в транзакции (10 вставок в транзакции выполняются быстрее, чем 10 вставок из транзакции и обычно получают / освобождают меньше блокировок)
  • Дайте ему отдохнуть. Выполняйте запись в вашу базу данных каждые N миллисекунд. Пакетные биты работ.
  • Если вам нужно составить исторический отчет, вы можете разбить таблицу журналов на разделы. Пример: Вы можете создавать новую таблицу журналирования каждый месяц, и в то же время иметь ПРОСМОТР ЖУРНАЛА, который является СОЮЗОМ ВСЕХ всех более старых таблиц журналирования. Выполните отчетность по наиболее подходящему источнику.

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

5 голосов
/ 13 июня 2009

Обычная вставка транзакции (т.е. READ COMMITTED) уже выполняет «минимальную» блокировку. Вставка интенсивных приложений не будет блокировать вставку, независимо от того, как вставка смешана с другими операциями. В худшем случае интенсивная система вставки может привести к конфликту защелок страницы в горячей точке, где происходит вставка, но не к блокировке.

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

  • Система использует более высокий уровень изоляции (у них она была тогда и вполне заслуживает этого)
  • Они читали из таблицы журнала во время транзакции (поэтому больше не «только для добавления»)
  • В цепочке взаимоблокировок задействованы блокировки прикладного уровня (т. Е. Операторы .Net lock в каркасе log4net), приводящие к необнаружимым тупикам (т. Е. Зависание приложения). Учитывая, что решение этой проблемы заключалось в рассмотрении дампов процессов, я полагаю, что это был их сценарий.

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

1 голос
/ 13 июня 2009

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

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

1 голос
/ 13 июня 2009

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

Также, если вы хотите минимизировать блокировку, вы должны постараться, чтобы как можно большая часть рабочей нагрузки вашего запроса покрывала некластеризованные индексы. (SQL Server 2005 и выше, использование оператора INCLUDE в индексах NC может иметь большое значение)

...