Мы сталкиваемся с распространенной проблемой: отчет на Системе Компоновки Данных (СКД) в 1С, который предназначен для анализа расходов на транспортные средства, формируется очень долго. В частности, если рассматривать данные за квартал, процесс может затянуться надолго. Отчет состоит из шести разных запросов, связанных по регистратору или транспортному средству. Вместе с вами разберем, как подойти к оптимизации такого отчета, выявим типичные ошибки и предложим эффективные решения.
Прежде всего, давайте выясним, где именно кроется "бутылочное горлышко" производительности. Медленная работа отчета СКД может быть вызвана как неоптимальным запросом к базе данных, так и сложной обработкой данных самой СКД.
Мы часто обнаруживаем, что медленная работа отчета обусловлена одной из следующих причин:
Ключевым шагом к оптимизации в нашей ситуации является переработка структуры отчета таким образом, чтобы он использовал один основной запрос (набор данных СКД) вместо шести отдельных. Этот единый запрос может быть довольно сложным и включать в себя внутренние объединения или соединения.
ОБЪЕДИНИТЬ ВСЕ или ЛЕВОЕ СОЕДИНЕНИЕ внутри себя. Это позволяет СУБД оптимальнее планировать выполнение и минимизировать передачу данных между сервером 1С и СУБД.ЛЕВОЕ СОЕДИНЕНИЕ: Если наши шесть запросов извлекают связанные данные для одних и тех же ключевых сущностей (например, для одного и того же Транспортного средства и Регистратора), мы можем попытаться объединить их с помощью ЛЕВОЕ СОЕДИНЕНИЕ. Это позволяет нам получить все данные в одном наборе, избегая повторных выборок из одних и тех же таблиц.ОБЪЕДИНИТЬ ВСЕ: Если же данные из разных запросов представляют собой принципиально разные типы показателей, которые нужно просто вывести одной "таблицей" (например, пробег, вес груза и расход ГСМ из разных регистров или с разными параметрами), то конструкция ОБЪЕДИНИТЬ ВСЕ внутри одного большого запроса будет уместной. Важно убедиться, что число полей и их типы в каждой ветке ОБЪЕДИНИТЬ ВСЕ совпадают.Рассмотрим пример одного из наших запросов (сообщение 9) и выясним, какие конкретные шаги по оптимизации мы можем предпринять.
ВЫБРАТЬ
Пробег.Регистратор КАК ПутевойЛист,
Пробег.ТС КАК ТС,
Пробег.Количество КАК Пробег,
0 КАК ВесГруза,
Пробег.Организация КАК Организация,
0 КАК КоличествоРасход,
0 КАК СтоимостьРасход
ИЗ
РегистрНакопления.уатВыработкаТС КАК Пробег
ГДЕ
Пробег.ПараметрВыработки = &Пробег
И Пробег.Период МЕЖДУ &НачалоПериода И &КонецПериода
И Пробег.ТС.Наименование <> &НаименованиеТС
ОБЪЕДИНИТЬ ВСЕ
ВЫБРАТЬ
ВесГруза.Регистратор,
ВесГруза.ТС,
0,
ВесГруза.Количество,
ВесГруза.Организация,
0,
0
ИЗ
РегистрНакопления.уатВыработкаТС КАК ВесГруза
ГДЕ
ВесГруза.ПараметрВыработки = &ВесГруза
И ВесГруза.Период МЕЖДУ &НачалоПериода И &конецПериода
И ВесГруза.ТС.Наименование <> &НаименованиеТС
ОБЪЕДИНИТЬ ВСЕ
ВЫБРАТЬ
уатОстаткиГСМнаТС.Регистратор,
уатОстаткиГСМнаТС.ТС,
0,
0,
уатОстаткиГСМнаТС.Организация,
уатОстаткиГСМнаТС.Количество,
уатОстаткиГСМнаТС.Стоимость
ИЗ
РегистрНакопления.уатОстаткиГСМнаТС КАК уатОстаткиГСМнаТС
ГДЕ
уатОстаткиГСМнаТС.ТС.Наименование <> &НаименованиеТС
И уатОстаткиГСМнаТС.Период МЕЖДУ &НачалоПериода И &конецПериода
И уатОстаткиГСМнаТС.ВидДвижения = &Расход
Наименование)Обратите внимание на условие Пробег.ТС.Наименование <> &НаименованиеТС. Это критически важная точка для оптимизации. Сравнение по строковому полю, особенно с оператором <> (не равно), может приводить к значительному замедлению работы запроса. Почему?
<> СУБД часто не может эффективно использовать индекс и вынуждена выполнять полное сканирование таблицы, проверяя каждую запись. Это особенно пагубно на больших объемах данных.Решение: Мы должны изменить условие фильтрации. Если мы хотим исключить конкретное транспортное средство, мы должны фильтровать по его ссылке, а не по наименованию. То есть, вместо передачи наименования в параметр &НаименованиеТС, мы должны передавать ссылку на объект ТС (например, из справочника) в новый параметр &ИсключаемоеТС.
Оптимизированное условие будет выглядеть так:
// ...
ГДЕ
// ...
И Пробег.ТС <> &ИсключаемоеТС
Если нам нужно исключить несколько ТС, мы можем использовать конструкцию НЕ В (СПИСОК):
// ...
ГДЕ
// ...
И Пробег.ТС НЕ В (&СписокИсключаемыхТС)
Для работы с регистрами накопления, такими как уатВыработкаТС и уатОстаткиГСМнаТС, мы должны активно использовать их виртуальные таблицы. Они специально оптимизированы для получения агрегированных данных за период и часто работают намного быстрее, чем прямые выборки из основной таблицы регистра.
В нашем запросе мы выбираем данные по Период МЕЖДУ &НачалоПериода И &КонецПериода. Это явный признак того, что мы можем (и должны) использовать виртуальные таблицы.
Обороты: Если нам нужны данные о приходе и расходе (обороты) за период.ОстаткиИОбороты: Если нужны начальный остаток, обороты и конечный остаток.СрезПоследних: Если нужен только последний остаток на определенную дату (актуально, если регистр остаточный).В нашем случае, для получения Пробег.Количество и ВесГруза.Количество, а также уатОстаткиГСМнаТС.Количество и уатОстаткиГСМнаТС.Стоимость за период, мы бы использовали виртуальную таблицу Обороты.
Пример использования виртуальной таблицы Обороты:
ВЫБРАТЬ
Обороты.Регистратор КАК ПутевойЛист,
Обороты.ТС КАК ТС,
СУММА(ВЫБОР КОГДА Обороты.ПараметрВыработки = &Пробег ТОГДА Обороты.Количество ИНАЧЕ 0 КОНЕЦ) КАК Пробег,
СУММА(ВЫБОР КОГДА Обороты.ПараметрВыработки = &ВесГруза ТОГДА Обороты.Количество ИНАЧЕ 0 КОНЕЦ) КАК ВесГруза,
Обороты.Организация КАК Организация,
СУММА(ВЫБОР КОГДА ОборотыГСМ.ВидДвижения = &Расход ТОГДА ОборотыГСМ.Количество ИНАЧЕ 0 КОНЕЦ) КАК КоличествоРасход,
СУММА(ВЫБОР КОГДА ОборотыГСМ.ВидДвижения = &Расход ТОГДА ОборотыГСМ.Стоимость ИНАЧЕ 0 КОНЕЦ) КАК СтоимостьРасход
ИЗ
РегистрНакопления.уатВыработкаТС.Обороты(&НачалоПериода, &КонецПериода, Регистратор, , ТС <> &ИсключаемоеТС) КАК Обороты
ЛЕВОЕ СОЕДИНЕНИЕ РегистрНакопления.уатОстаткиГСМнаТС.Обороты(&НачалоПериода, &КонецПериода, Регистратор, , ТС <> &ИсключаемоеТС) КАК ОборотыГСМ
ПО Обороты.Регистратор = ОборотыГСМ.Регистратор
ГДЕ
Обороты.ТС <> &ИсключаемоеТС
СГРУППИРОВАТЬ ПО
Обороты.Регистратор,
Обороты.ТС,
Обороты.Организация
Разберем этот пример:
РегистрНакопления.уатВыработкаТС.Обороты(...) и РегистрНакопления.уатОстаткиГСМнаТС.Обороты(...), передавая в них параметры периода и фильтрации.Обороты мы уже можем указать условие ТС <> &ИсключаемоеТС, что позволит СУБД отфильтровать данные на самом раннем этапе.Регистратор с помощью ЛЕВОЕ СОЕДИНЕНИЕ, так как нам нужны данные из обоих регистров.ВЫБОР КОГДА ... ТОГДА ... ИНАЧЕ 0 КОНЕЦ и агрегатной функции СУММА мы формируем нужные поля (Пробег, ВесГруза, КоличествоРасход, СтоимостьРасход) из различных параметров выработки или видов движения.СГРУППИРОВАТЬ ПО для всех неагрегированных полей.Этот подход позволяет нам объединить три секции из исходного запроса в одну, используя более эффективные виртуальные таблицы и корректную фильтрацию по ссылке.
ПОМЕСТИТЬ): Если запрос становится слишком сложным, и нам нужно выполнить несколько логических шагов обработки данных, мы можем использовать временные таблицы с конструкцией ПОМЕСТИТЬ. Это позволяет разбить сложный запрос на более простые, промежуточные этапы, где каждый этап может быть оптимизирован отдельно.Помимо оптимизации самого текста запроса, мы должны уделить внимание настройкам базы данных и самой СКД.
Убедитесь, что поля, по которым происходят соединения, фильтрация и группировка, проиндексированы. В 1С платформе многие индексы создаются автоматически, но для сложных или нестандартных запросов может потребоваться анализ существующих индексов и, при необходимости, создание новых. Для нашего случая это:
Период в регистрах накопления.Регистратор в регистрах накопления.ТС (ссылка) в регистрах накопления.ПараметрВыработки в регистре уатВыработкаТС.ВидДвижения в регистре уатОстаткиГСМнаТС.Правильно настроенные индексы значительно ускоряют поиск и фильтрацию данных, предотвращая полные сканирования таблиц.
Даже самый быстрый запрос может быть замедлен неоптимальными настройками СКД:
Для выявления самых тонких мест в производительности отчетов СКД мы можем использовать технологический журнал 1С. Он позволяет получить детальную информацию о времени выполнения каждого этапа формирования отчета:
Анализируя логи технологического журнала, мы можем точно определить, какой из этапов занимает больше всего времени и на чем следует сосредоточить наши усилия по оптимизации.
Таким образом, для оптимизации нашего отчета мы должны последовательно провести диагностику, переработать структуру запросов, используя единый оптимизированный запрос с виртуальными таблицами и корректными условиями фильтрации, а также уделить внимание настройкам СКД и индексам базы данных. Эти шаги помогут нам значительно ускорить формирование отчета и обеспечить его эффективную работу.