Что я могу сделать, чтобы программно предотвратить или ограничить ресурсные споры?
Я создал приложение, которое, учитывая достаточное количество данных, не может быть завершено: "Журнал транзакций для базы данных" tempdb "заполнен из-за ACTIVE_TRANSACTION". " и "Не удается найти таблицу 0".
Хранимая процедура, используемая в отчете, явно не ссылается на "tempdb", поэтому она должна быть чем-то, что SQL Server управляет самостоятельно.
Во всяком случае, я провел анализ "Resource Contention" в Visual Studio 2013 через Analyze > Performance and Diagnostics.
Когда он закончил, он сообщил мне в "Отчете о профилировании параллелизма", что было 30 790 общих конфликтов, причем "Handle2" и "Multiple Handles 1" составляли более 99% "Наиболее конфликтующих ресурсов" и "_CorExeMain", идентификатора потока 4936 как "Самая обсуждаемая тема"
Думаю, все это достаточно интересно, но теперь, когда я это знаю, что я могу с этим поделать?
Является ли 30,790 чрезмерным количеством общих споров? Звучит так, но я не знаю. Но опять же, если предположить, что эта информация на самом деле не говорит мне ничего ценного, а именно: что я могу сделать, чтобы улучшить ситуацию? Как программно предотвратить или ограничить конфликт ресурсов и / или потоков?
В сгенерированном отчете не было ошибок, и шесть сообщений были "только для информации". Было одно предупреждение:
Предупреждение 1 DA0022: Коллекции # Gen 1 / Коллекции # Gen 2 = 2.52; Относительно высокий уровень сбора мусора в Gen 2. Если, по замыслу, большинство структур данных вашей программы выделены и сохраняются в течение длительного времени, это обычно не является проблемой. Однако, если это поведение непреднамеренно, ваше приложение может прикреплять объекты. Если вы не уверены, вы можете собрать данные о распределении памяти.NET и информацию о времени жизни объекта, чтобы понять, как распределено использование памяти вашим приложением.
... но сохранение структур данных в течение "долгого времени", действительно, задумано.
ОБНОВИТЬ
Затем я запустил отчет ".NET Memory Allocation", и здесь я тоже не уверен, что с ним делать:
Является ли 124 миллиона байтов избыточным? Есть ли что-то плохое в функциях, выделяющих наибольшее количество памяти, или на какие типы выделяется наибольшее количество памяти?
Я также не понимаю, почему красная вертикальная линия перемещается после создания отчета; сначала он был около 616, затем переместился на 0 (как видно на скриншоте выше), а теперь около 120.
ОБНОВЛЕНИЕ 2
Теперь я вижу (после выполнения окончательной проверки производительности (Instrumentation)), что вертикальная красная линия - это просто лемминг - она следует за курсором, куда бы вы его ни перетащили. Это имеет какую-то цель, я думаю...
1 ответ
Вот что в итоге сработало: двусторонняя атака:
0) Гуру базы данных реорганизовал хранимую процедуру, чтобы сделать ее более эффективной.
1) Я переработал код чтения данных, разбив его на две части. Я определил первую половину данных, которые нужно извлечь, и получил их, затем последовал короткую паузу со вторым проходом, извлекая остальные данные. Короче что раньше было так:
. . .
ReadData(_unit, _monthBegin, _monthEnd, _beginYearStr, _endYearStr);
. . .
... теперь это:
. . .
if // big honkin' amount of data
{
string monthBegin1 = _monthBegin;
string monthEnd1 = GetEndMonthOfFirstHalf(_monthBegin, _monthEnd, _beginYearStr, _endYearStr);
string monthBegin2 = GetBeginMonthOfSecondHalf(_monthBegin, _monthEnd, _beginYearStr, _endYearStr);
string monthEnd2 = _monthEnd;
string yearBegin1 = _beginYearStr;
string yearEnd1 = GetEndYearOfFirstHalf(_monthBegin, _monthEnd, _beginYearStr, _endYearStr);
string yearBegin2 = GetBeginYearOfSecondHalf(_monthBegin, _monthEnd, _beginYearStr, _endYearStr);
string yearEnd2 = _endYearStr;
ReadData(_unit, monthBegin1, monthEnd1, yearBegin1, yearEnd1);
Thread.Sleep(10000);
ReadData(_unit, monthBegin2, monthEnd2, yearBegin2, yearEnd2);
}
else // a "normal" Unit (not an overly large amount of data to be processed)
{
ReadData(_unit, _monthBegin, _monthEnd, _beginYearStr, _endYearStr);
}
. . .
Теперь он успешно работает до завершения без каких-либо исключений. Я не знаю, была ли проблема полностью связана с базой данных, или если все действия Excel Interop также были проблемными, но теперь я могу сгенерировать файлы Excel размером 1341 КБ с помощью этой операции.