Как в СКД вывести обороты за разные периоды в одну строку без потери производительности?

Программист 1С v8.3 (Управляемые формы) 1С:Розница Управленческий учет Торговля и дистрибуция
← На главную

При разработке аналитических отчетов по продажам часто возникает задача сформировать сводную матрицу показателей по номенклатуре. Типичный пример — необходимость вывести в единой строке по каждому товару данные: Продано за день, за неделю, за декаду, за месяц, за квартал и за год.

Решение «в лоб» через объединение множества запросов (ОБЪЕДИНИТЬ ВСЕ) или множественные левые соединения одной и той же таблицы существенно увеличивает нагрузку на СУБД, особенно в розничных базах с десятками магазинов и детализацией до серий и партий. Разберем наиболее эффективные и архитектурно правильные способы реализации такого отчета в Системе компоновки данных (СКД).

Способ 1. Условное агрегирование в тексте запроса (ВЫБОР КОГДА)

Разберем самый производительный вариант с точки зрения выполнения запроса СУБД. Вместо нескольких обращений к базе данных мы считываем данные из регистра ровно один раз за максимальный период (например, за текущий год) с детализацией по дням, а разделение по колонкам периодов производим с помощью агрегатных функций с условием.

Посмотрим на пример текста запроса в наборе данных СКД:


ВЫБРАТЬ
    ПродажиОбороты.Номенклатура КАК Номенклатура,
    ПродажиОбороты.Склад КАК Склад,
    СУММА(ВЫБОР
            КОГДА ПродажиОбороты.ПериодДень >= &НачалоДня
                ТОГДА ПродажиОбороты.КоличествоОборот
            ИНАЧЕ 0
        КОНЕЦ) КАК ПродажиЗаДень,
    СУММА(ВЫБОР
            КОГДА ПродажиОбороты.ПериодДень >= &НачалоНедели
                ТОГДА ПродажиОбороты.КоличествоОборот
            ИНАЧЕ 0
        КОНЕЦ) КАК ПродажиЗаНеделю,
    СУММА(ВЫБОР
            КОГДА ПродажиОбороты.ПериодДень >= &НачалоМесяца
                ТОГДА ПродажиОбороты.КоличествоОборот
            ИНАЧЕ 0
        КОНЕЦ) КАК ПродажиЗаМесяц,
    СУММА(ВЫБОР
            КОГДА ПродажиОбороты.ПериодДень >= &НачалоКвартала
                ТОГДА ПродажиОбороты.КоличествоОборот
            ИНАЧЕ 0
        КОНЕЦ) КАК ПродажиЗаКвартал,
    СУММА(ПродажиОбороты.КоличествоОборот) КАК ПродажиЗаГод
ИЗ
    РегистрНакопления.Продажи.Обороты(&НачалоГода, &КонецГода, День, ) КАК ПродажиОбороты
СГРУППИРОВАТЬ ПО
    ПродажиОбороты.Номенклатура,
    ПродажиОбороты.Склад

Проанализируем параметры этого решения:

  1. В параметрах виртуальной таблицы указывается периодичность День, а начальная дата устанавливается на &НачалоГода.
  2. На вкладке Параметры СКД для служебных дат (&НачалоДня, &НачалоНедели, &НачалоМесяца) задаются стандартные выражения платформы 1С: НачалоПериода(&КонецПериода, "День"), НачалоПериода(&КонецПериода, "Неделя") и т.д.
  3. Флажки доступности этих параметров для пользователя снимаются, пользователю остается доступен только ввод рабочей даты отчета.

Способ 2. Настройка группировок с отборами на уровне структуры СКД

Если требуется сохранить стандартную структуру выборки с периодичностью и не перегружать текст запроса условными конструкциями, применим механизм отборов на уровне группировок.

Разберем по шагам порядок настройки:

  1. В запросе выбираются стандартные поля регистра с периодичностью День, Неделя, Месяц, Квартал.
  2. На вкладке Настройки в структуре отчета создается группировка строк по номенклатуре.
  3. Внутри группировки или в колонках таблицы создаются параллельные группировки по соответствующим полям периодов.
  4. Для каждой отдельной группировки периода настраивается собственный локальный отбор: например, для группировки по неделе задается условие ПериодНеделя = &ТекущаяНеделя, для месяца — ПериодМесяц = &ТекущийМесяц.

Способ 3. Вычисление выражений в ресурсах схемы компоновки

СКД предоставляет богатый набор встроенных функций языка выражений. Мы можем получить детальные записи по дням в едином наборе данных, а расчет колонок за определенные интервалы перенести на вкладку Ресурсы.

Для каждого создаваемого поля ресурса (например, ПроданоЗаНеделю) в колонке Выражение указывается формула с агрегацией массива значений, отфильтрованных по дате:


Сумма(ВычислитьВыражениеСГруппировкойМассив("КоличествоОборот", "ПериодДень", "ПериодДень >= &ДатаНачалаНедели"))

Такой способ оставляет запрос лаконичным, перекладывая агрегацию на внутренний процессор компоновки данных.

Почему отчет может работать медленно и как его ускорить

При больших объемах продаж (крупные торговые сети, тысячи чеков в день) пользователи нередко сталкиваются с зависанием отчета. Выясним основные причины снижения производительности и способы их устранения:

  1. Фильтрация в секции ГДЕ вместо параметров виртуальной таблицы: Если отборы по номенклатуре, магазину или складу наложить в секции ГДЕ, СУБД сначала прочитает весь регистр за год и только потом отсечет ненужное. Обязательно передавайте все отборы внутрь круглых скобок виртуальной таблицы: РегистрНакопления.Продажи.Обороты(&НачалоГода, &КонецГода, День, Номенклатура В (&Номенклатура) И Склад = &Склад).
  2. Опасность периодичности «Авто»: Использование значения Авто заставляет платформу строить сложные динамические планы запросов с обращением к таблицам итогов и регистраторов. Для скользящих аналитических срезов рекомендуется жестко задавать периодичность День.
  3. Порядок измерений в регистре накопления: Индексы таблиц итогов формируются строго по порядку следования измерений в дереве метаданных конфигуратора. Если фильтрация идет по номенклатуре и складу, но перед ними стоят другие измерения, стандартный индекс СУБД работать не будет.
  4. Актуальность итогов регистра: Если итоги по регистру не рассчитаны или отключено использование агрегатов, платформа будет рассчитывать обороты сканированием первичных таблиц движений документов, что кратно замедляет выполнение отчета за длительные интервалы.
← На главную