При работе с крупными базами данных на платформе 1С:Управление производственным предприятием (УПП) разработчики часто сталкиваются с деградацией производительности. Основные «тормоза» обычно локализованы в механизмах проведения документов по регистрам накопления, процедурах удаления старых движений и специфических запросах РАУЗ (Расширенная аналитика учета затрат). Рассмотрим пошагово, как можно оптимизировать эти процессы и на что обратить внимание в первую очередь.
В типовых решениях УПП в модуле объекта часто встречается логика инициализации переменной мУдалятьДвижения. По умолчанию 1С использует конструкцию мУдалятьДвижения = НЕ ЭтоНовый();. Проблема заключается в том, что вызов метода Записать() для пустого набора записей регистра (даже если движений никогда не было, но документ не новый) инициирует транзакционный запрос к СУБД для удаления записей по регистратору. В высоконагруженных системах запись пустого набора может занимать до 50% времени проведения документа.
Проанализируем ситуацию: проверять флаг Проведен при записи не всегда эффективно, так как в момент записи этот флаг может уже содержать «будущее» состояние документа. Вместо безусловной очистки всех регистров, которые прописаны в метаданных документа, рекомендуем внедрить механизм «избирательной очистки».
Разберем алгоритм оптимизации этого блока:
НаборЗаписей.Записать() добавим проверку: если набор пуст И в базе данных по этому регистратору записей нет (проверяется легким запросом), вызов метода Записать() следует пропустить.Прочитать(), чтобы проверить наличие существующих движений перед их удалением.В документах типа «Отчет производства за смену» (ОПЗС) при использовании РАУЗ огромная часть времени (иногда до 80%) уходит на выполнение запроса в функции СформироватьТаблицуАналитики. Выясним причину такой медлительности: запрос выполняет тяжелые соединения с таблицами аналитик вида учета и распределения затрат.
Часто этот запрос выполняется впустую, если в базе настроен режим допроведения (отложенного проведения). В этом режиме движения по бухгалтерскому и управленческому учету формируются позже регламентным заданием, а в самом документе флаги ОтражатьВБухгалтерскомУчете и ОтражатьВУправленческомУчете установлены в Ложь. Однако типовой код все равно выполняет подготовку данных.
Для оптимизации этого узла выполним следующие действия:
Проанализируем условия выполнения запроса. Если документ проводится только для оперативного учета или в режиме отложенного проведения, мы можем модифицировать текст запроса, исключив из него блоки, связанные с формированием данных для видов учета, которые в данный момент неактивны. Рассмотрим пример модификации кода:
Если НЕ СтруктураШапкиДокумента.ОтражатьВБухгалтерскомУчете
И НЕ СтруктураШапкиДокумента.ОтражатьВУправленческомУчете Тогда
// Пропускаем формирование тяжелой таблицы аналитик,
// если она не нужна для текущих целей проведения
Возврат Новый ТаблицаЗначений;
КонецЕсли;
Такая простая проверка позволяет значительно сократить время отклика системы для пользователей, работающих «в потоке».
Если в базе работают более 100-200 пользователей, стандартных настроек СУБД становится недостаточно. Посмотрим, какие параметры критически важны для УПП:
Max Degree of Parallelism в значение 1. Это гарантирует, что один неоптимальный запрос не «отъест» все ядра процессора, парализовав работу остальных пользователей.УчетЗатрат, ПартииТоваровНаСкладах) на управляемые блокировки дает колоссальный эффект.Если ваше предприятие использует классический партионный учет, основной проблемой становятся вложенные запросы внутри циклов или соединений. Проанализируем типичную ошибку: использование конструкции ВЫБРАТЬ... ИЗ (ВЫБРАТЬ...) в соединении. SQL-оптимизатор часто не может построить эффективный план для таких конструкций.
Рекомендуем переделать такие участки кода следующим образом:
МенеджерВременныхТаблиц).Рассмотрим пример правильной работы с временными таблицами:
Запрос = Новый Запрос;
Запрос.МенеджерВременныхТаблиц = Новый МенеджерВременныхТаблиц;
Запрос.Текст =
"ВЫБРАТЬ
| ТаблицаТовары.Номенклатура,
| ТаблицаТовары.Количество
|ПОМЕСТИТЬ ВТ_Товары
|ИЗ
| &ТаблицаТовары КАК ТаблицаТовары
|ИНДЕКСИРОВАТЬ ПО
| Номенклатура";
Запрос.Выполнить();
Часто проблемы с производительностью связаны не с кодом, а с состоянием базы данных. Разберем основные моменты обслуживания:
Пересчет итогов: При массовом перепроведении документов «задним числом» актуальность итогов регистров накопления может смещаться. Если дата актуальности итогов сильно отстает от текущей даты, 1С начинает вычислять остатки динамически по таблице движений, что крайне медленно. Следите за тем, чтобы итоги были рассчитаны на конец текущего или следующего месяца.
Фрагментация индексов: В УПП таблицы регистров УчетЗатрат могут достигать гигантских размеров. При активной записи индексы фрагментируются. Настройте ежедневное (а в пиковые периоды — и более частое) обновление статистики SQL и реорганизацию индексов для «горячих» таблиц.
В заключение отметим, что оптимизация УПП — это комплексный процесс. Начав с устранения избыточных вызовов Записать() в наборах записей и ограничив выполнение тяжелых запросов в ОПЗС, вы сможете выиграть до 50-70% времени проведения документов без кардинальной переработки всей системы.