При работе с большими объемами данных в системе компоновки данных (СКД) разработчики часто сталкиваются с проблемами производительности: отчет может формироваться крайне долго, "зависать" на определенном проценте вывода или вовсе завершаться с ошибкой "Недостаточно памяти на сервере". Рассмотрим комплексный подход к оптимизации таких отчетов, основываясь на практическом опыте и архитектурных особенностях платформы 1С.
Проанализируем типичную ошибку в структуре запроса. Использование вложенных запросов (когда один ВЫБРАТЬ находится внутри другого) — это основной фактор замедления. СУБД (например, MS SQL Server) сложно построить оптимальный план выполнения для "матрешки" из запросов, особенно если их глубина велика.
Рассмотрим, как следует преобразовать запрос. Вместо конструкции:
ВЫБРАТЬ
ПланФакт.Контрагент,
ПланФакт.Сумма
ИЗ
(ВЫБРАТЬ ... ИЗ РегистрНакопления.Продажи.Обороты(...) КАК Продажи) КАК ПланФакт
Мы должны использовать временные таблицы.
Пример оптимизированной структуры:
ВЫБРАТЬ
ПродажиОбороты.ДоговорКонтрагента.Владелец КАК Контрагент,
ПродажиОбороты.СтоимостьОборот КАК Сумма
ПОМЕСТИТЬ ВТ_Продажи
ИЗ
РегистрНакопления.Продажи.Обороты(&НачалоПериода, &КонецПериода, , ) КАК ПродажиОбороты;
ИНДЕКСИРОВАТЬ ПО
Контрагент;
////////////////////////////////////////////////////////////////////////////////
ВЫБРАТЬ
ВТ_Продажи.Контрагент,
СУММА(ВТ_Продажи.Сумма) КАК Сумма
ИЗ
ВТ_Продажи КАК ВТ_Продажи
СГРУППИРОВАТЬ ПО
ВТ_Продажи.Контрагент
Как показывает практика, такая замена может ускорить выполнение запроса в десятки и даже сотни раз за счет эффективного использования индексов и предсказуемого плана выполнения SQL.
Часто в отчетах требуется определить "уровень" объекта или найти его родителя на определенной глубине (например, бренд верхнего уровня). Использование конструкций вида Номенклатура.Бренд.Родитель.Родитель крайне неэффективно, так как порождает цепочку левых соединений (Left Join) в SQL-запросе для каждой строки данных.
Проанализируем ситуацию: если нам нужно сгруппировать данные по иерархии брендов, лучше доверить это самой СКД. Вместо того чтобы вычислять уровни в запросе, выберем плоский список элементов, а в настройках структуры СКД укажем тип группировки "Иерархия". Платформа 1С оптимизирует построение дерева гораздо лучше, чем ручные проверки в тексте запроса.
Если же необходимо ограничить выборку конкретными узлами иерархии, используйте оператор В ИЕРАРХИИ в параметрах виртуальных таблиц или в секции ГДЕ, предварительно подготовив список нужных родителей во временной таблице.
Выясним причину долгого получения данных из регистров. Огромная ошибка — не указывать параметры (период, условия) непосредственно в виртуальной таблице, а накладывать их позже в секции ГДЕ.
Неправильно:
РегистрНакопления.Продажи.Обороты() КАК Продажи ГДЕ Продажи.Период МЕЖДУ &Дата1 И &Дата2
Правильно:
РегистрНакопления.Продажи.Обороты(&Дата1, &Дата2, , ) КАК Продажи
В СКД параметры виртуальных таблиц обычно подставляются автоматически, но при использовании вложенных запросов или временных таблиц этот механизм может "сломаться". Всегда проверяйте, чтобы условия накладывались на самом раннем этапе выборки данных.
Проанализируем процесс вывода данных. Даже если запрос работает быстро, отчет может "висеть" на этапе формирования табличного документа. Рассмотрим три ключевых настройки:
ПараметрыВывода.ВыводитьРасшифровку = Ложь. Это существенно экономит оперативную память, так как системе не нужно хранить информацию о связи каждой ячейки с объектами базы данных.Если вы получаете ошибку "Недостаточно памяти", важно понимать, как работает сервер 1С. В 32-битных версиях сервера рабочий процесс rphost ограничен адресным пространством в 4 Гб (на практике — около 3 Гб). При формировании гигантского отчета СКД пытается собрать все данные в памяти этого процесса.
Рассмотрим способы решения этой проблемы:
ВЫРАЗИТЬ() для полей составного типа. Это избавляет систему от избыточных соединений с таблицами всех возможных типов данных, входящих в составное поле.Посмотрим на пример того, как избежать неявных вызовов к базе данных. При обращении через точку к полям ссылочных объектов (например, Продажи.Контрагент.Наименование), система делает неявное соединение.
Чтобы ускорить вывод, используйте функцию ПРЕДСТАВЛЕНИЕ(Продажи.Контрагент) КАК КонтрагентПредставление в запросе. СКД умеет эффективно работать с представлениями, получая их в один проход вместе с основными данными.
Также стоит избегать функций от параметров внутри запроса. Например, вместо КОНЕЦПЕРИОДА(&ДатаКон, МЕСЯЦ) лучше передать в запрос уже готовую и вычисленную дату через программную установку параметров.
Соблюдение этих правил позволит вам создавать быстрые и стабильные отчеты даже на самых нагруженных информационных базах.