Что выбрать в СКД для повышения производительности: несколько наборов данных или один запрос с временными таблицами?

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

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

Внутренняя механика: где и как обрабатываются данные

Главное различие между этими подходами заключается в том, на каком физическом узле информационной системы выполняется соединение и сопоставление записей:

  1. Один набор данных (пакетный запрос с временными таблицами): вся логика выборки, промежуточной фильтрации и соединения таблиц выполняется непосредственно на сервере СУБД (SQL). Сервер 1С отправляет один пакетный запрос и получает уже готовый консолидированный результат. Промежуточные данные можно индексировать по полям соединения с помощью конструкции ИНДЕКСИРОВАТЬ ПО.
  2. Несколько связанных наборов данных: запросы к СУБД выполняются последовательно для каждого набора. Само соединение строк происходит в оперативной памяти процесса сервера приложений «1С:Предприятие» (ragent / rphost), а не средствами СУБД.

Рассмотрим подробнее, как именно СКД обрабатывает связи наборов данных. Если в настройках связи не передан параметр в подчиненный набор, сервер 1С сначала выполнит запрос главного набора, затем полностью выполнит запрос подчиненного набора без ограничений и только потом выполнит их сшивание в памяти. Если же связь настроена через параметр подчиненного набора, СКД формирует запросы к СУБД пачками параметров под строки главного набора. При больших объемах данных это порождает проблему «N+1 запросов», создавая избыточную нагрузку на сеть и процессор СУБД.

Когда следует использовать временные таблицы в одном наборе

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

  1. Большой объем записей: при обработке десятков и сотен тысяч строк механизмы оптимизации SQL-сервера, использование индексов и работа с буферным пулом СУБД работают в разы быстрее, чем передача сырых выборок по сети и их обработка виртуальной машиной 1С.
  2. Сложные условия соединений: если требуется связать данные по составным ключам, диапазонам дат, условиям «больше/меньше» или с применением выражений (ВЫБОР КОГДА...), реализовать это на вкладке «Связи наборов данных» невозможно или крайне неэффективно. На уровне языка запросов такие соединения отрабатывают прозрачно.
  3. Многократная предварительная фильтрация: временные таблицы позволяют сразу отсечь нерелевантные записи на раннем этапе (например, выбрать только актуальные срезы регистров сведений с отбором по организации), что снижает объем сканируемых данных.
  4. Удобочитаемость и поддержка: структурированный пакет запросов во встроенном конструкторе проще анализировать, профилировать в консоли запросов и дорабатывать другим разработчикам.

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


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

ВЫБРАТЬ
    Остатки.Номенклатура КАК Номенклатура,
    Остатки.ВНаличииОстаток КАК Остаток
ПОМЕСТИТЬ ВТ_Остатки
ИЗ
    РегистрНакопления.Запасы.Остатки(&КонецПериода, ) КАК Остатки
ИНДЕКСИРОВАТЬ ПО
    Номенклатура
;

ВЫБРАТЬ
    ВТ_Продажи.Номенклатура КАК Номенклатура,
    ВТ_Продажи.Количество КАК Количество,
    ВТ_Продажи.Сумма КАК Сумма,
    ЕСТЬNULL(ВТ_Остатки.Остаток, 0) КАК Остаток
ИЗ
    ВТ_Продажи КАК ВТ_Продажи
        ЛЕВОЕ СОЕДИНЕНИЕ ВТ_Остатки КАК ВТ_Остатки
        ПО ВТ_Продажи.Номенклатура = ВТ_Остатки.Номенклатура

Когда оправдано использование нескольких наборов данных

Несмотря на преимущества временных таблиц в СУБД, существуют сценарии, в которых механизм связей наборов данных СКД является единственно верным или наиболее простым архитектурным решением:

  1. Разнородные источники информации: если отчет должен объединить данные из базы данных 1С (Набор данных - запрос) и внешние структуры (например, Набор данных - объект, содержащий сформированную программно таблицу значений, результат веб-сервиса или внешнего файла). В этом случае выполнить соединение на стороне SQL физически невозможно.
  2. Проблема независимых связей «один-ко-многим» (декартово произведение): классическая задача, когда к одному объекту (например, ЗаказКлиента) нужно присоединить две независимые подчиненные таблицы — список оплат и список отгрузок. Если соединить их левым соединением в одном запросе, строки перемножатся, что приведет к искажению суммовых итогов (ресурсов). Связывание наборов данных в СКД решает эту проблему автоматически: иерархия группировок строится без дублирования числовых показателей.
  3. Показатели с разной гранулярностью: если требуется вывести общие плановые показатели по подразделению рядом с детальными строками операций конкретных сотрудников, использование связей наборов избавляет от необходимости писать тяжелые вложенные подзапросы с искусственными группировками.

Рекомендации по оптимизации отчетов

Выясним правила, которые помогут добиться максимальной скорости формирования отчетов:

  1. Для типовых учетных выборок всегда используем один набор данных — запрос и временные таблицы с явным индексированием полей связи.
  2. Если необходимо объединить несколько параллельных однотипных таблиц (например, остатки по разным регистрам), вместо связей наборов используем конструкцию ОБЪЕДИНИТЬ ВСЕ в запросе либо объект СКД Набор данных - объединение.
  3. Если использование нескольких наборов данных неизбежно, обязательно настраиваем связь через параметр подчиненного набора, чтобы подчиненный запрос не считывал всю таблицу из базы данных целиком.
  4. При настройке связей наборов данных устанавливаем флаг «Обязательная связь» только в тех случаях, когда подчиненные данные действительно требуются при любом варианте пользовательских настроек колонок.
← На главную