Возможно, это не связано, но я заметил, что в некоторых тестах, которые я проводил сегодня, мои юнит-тесты, казалось, работали медленнее и медленнее. Случайно я вышел из / перезапустил Visual Studio, и мои тесты теперь намного быстрее. В механизме модульного тестирования может быть какая-то утечка памяти или другие проблемы с ресурсами. Я запускаю обновление 1.
Вставка обычной транзакции (т.е. READ COMMITTED) уже выполняет «минимальную» блокировку. Приложения с интенсивной вставкой не будут блокировать вставку, независимо от того, в каком порядке вставка смешивается с другими операциями. В худшем случае, интенсивная система вставки может вызвать конкуренцию за защелку страницы в горячей точке, где происходит вставка, но не может вызвать взаимоблокировки.
Чтобы вызвать взаимоблокировки, как описано Джеффом, должно быть что-то большее, например, любое из следующего:
lock
в структуре log4net), приводящие к необнаруживаемым взаимоблокировкам (т.е. приложение зависает). Учитывая, что решение проблемы заключалось в просмотре дампов процессов, я предполагаю, что это был тот сценарий, который они имели. Так что, пока вы вставляете только регистрацию в транзакции уровня изоляции READ COMMITTED, вы в безопасности. Если вы ожидаете той же проблемы, которая, как я подозреваю, была у SO (т. Е. Тупиковые ситуации, связанные с блокировками на уровне приложений), то никакое количество волшебных средств базы данных не может вас спасти, поскольку проблема все равно может проявиться, даже если вы входите в отдельную транзакцию или в отдельное соединение.
Поскольку вы не заботитесь о транзакционной целостности таблицы аудита, вы, очевидно, можете вести журнал вне транзакции (то есть после ее завершения). Это минимизирует влияние на транзакцию.
Кроме того, если вы хотите минимизировать блокировку, вы должны попытаться убедиться, что как можно большая часть вашей рабочей нагрузки запросов покрывает некластеризованные индексы. (SQL Server 2005 и более поздние версии, использование оператора INCLUDE
в индексах NC может иметь большое значение)
Один из простых способов предотвратить возникновение проблем с блокировкой при ведении журнала с «обычной» базой данных - это не использовать одну и ту же базу данных. Просто создайте еще одну базу данных для ведения журнала. В качестве бонуса быстрый рост вашей базы данных журналов не приведет к фрагментации вашей основной БД. Лично я обычно предпочитаю вести журнал в файл - но опять же, я привык выполнять тяжелые манипуляции с текстом в своем редакторе - VIM. Ведение журнала в отдельную базу данных должно помочь избежать проблем с взаимоблокировкой.
Просто убедитесь, что если вы попытаетесь написать собственный прикладник базы данных для используемой вами инфраструктуры ведения журнала, вы будете очень осторожны со своими блокировками (я предполагаю, что это то, что привело Джеффа в сообщении блога, на которое вы ссылаетесь). Правильно написано (см. Несколько комментариев в сообщении Джеффа), вы не должны
If you don't care about consistency on your logging table, why not perform all the logging from a separate thread.
I probably would not wait for transactions to complete before logging, since the log can be pivotal in diagnosing long running transactions. Also, this enables you to see all the work a transaction that rolled back did.
Grab the stack trace and all of your logging data in the logging thread, chuck it on a queue when there are new logging messages, flush them to the db in a single transaction.
Steps to minimizing locking:
You will get better performance by flushing multiple logging messages in a single (smallish) transaction, and have the advantage that if 10 threads are doing work and logging stuff, only a single thread is flushing stuff to the logging table. This pipelining actually makes stuff scale better.