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