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

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

При разработке сложных отчетов на системе компоновки данных (СКД) часто возникает задача получения информации из одного и того же источника, но с разными входными параметрами. Типичный пример — необходимость вывести остатки товаров на две разные даты в одной строке отчета или получить цены разных типов. В этой статье мы разберем, как правильно организовать архитектуру наборов данных, чтобы отчет работал быстро и эффективно.

Анализируем проблему: почему стандартные связи могут тормозить отчет

Рассмотрим типичную ситуацию: у нас есть основной запрос (НаборДанных1), который выбирает список номенклатуры, и вспомогательный запрос (НаборДанных2), который получает остатки. Если мы попытаемся связать их на вкладке Связи наборов данных дважды, передавая в Параметры разные даты, мы можем столкнуться с резким падением производительности. Выясним причину этого явления.

Когда мы настраиваем связь между наборами данных в СКД, платформа 1С зачастую выполняет так называемый "эффект N+1". Это означает, что для каждой строки, полученной в первом наборе данных, система будет выполнять отдельный запрос ко второму набору данных. Если в первом наборе 1000 строк, то ко второму набору будет сделано 1000 обращений. Если же мы связываем наборы дважды, количество запросов удваивается. Это основная причина того, почему отчет "еле ворочается".

Решение 1: Объединение данных в одном запросе (Набор данных - запрос)

Это самый эффективный и рекомендуемый способ. Вместо того чтобы создавать два отдельных набора данных и связывать их средствами СКД, мы объединим всю логику в одном тексте запроса. Это позволит SQL-серверу оптимизировать план выполнения и выдать результат одним махом.

Разберем, как это реализовать на примере получения остатков на две разные даты. Мы можем использовать левое соединение с одной и той же виртуальной таблицей, но с разными параметрами и псевдонимами. Рассмотрим пример кода:


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

Преимущества данного метода:

  1. Минимальное количество обращений к базе данных (всего один SQL-запрос).
  2. Высокая скорость выполнения за счет оптимизации на стороне СУБД.
  3. Простота отладки в консоли запросов.

Решение 2: Использование временных таблиц и пакетных запросов

Если логика получения данных во втором наборе слишком сложная и простое ЛЕВОЕ СОЕДИНЕНИЕ перегружает запрос, проанализируем вариант с использованием временных таблиц. Мы можем сначала подготовить все необходимые данные во временную таблицу, а затем соединить их с основным результатом.

Посмотрим на пример структуры пакетного запроса:


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

// Второй запрос пакета: основная выборка
ВЫБРАТЬ
    Номенклатура.Ссылка,
    ВТ_Остатки.Остаток
ИЗ
    Справочник.Номенклатура КАК Номенклатура
        ЛЕВОЕ СОЕДИНЕНИЕ ВТ_Остатки КАК ВТ_Остатки
        ПО Номенклатура.Ссылка = ВТ_Остатки.Номенклатура

Этот подход особенно полезен, когда данные нужно предварительно сгруппировать или отфильтровать. Использование МенеджерВременныхТаблиц позволяет передавать эти таблицы между разными наборами данных, если отчет формируется программно.

Решение 3: Вычисляемые поля и функции общих модулей

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

Мы можем создать в СКД Вычисляемое поле и в колонке "Выражение" вызвать функцию общего модуля:

ОбщийМодульОтчеты.ПолучитьСпецифическийПоказатель(Номенклатура, &ПараметрДаты)

Важные нюансы:

Решение 4: Работа с внешними источниками данных

Проанализируем ситуацию, упомянутую в обсуждении: что делать, если данные поступают из разных внешних баз? Если мы попытаемся связать их напрямую в СКД, производительность будет крайне низкой, так как 1С будет выполнять сопоставление в памяти своего сервера.

В этом случае рекомендуется рассмотреть возможность использования технологии Linked Server (Связанные серверы) на уровне СУБД (MS SQL Server или PostgreSQL). Это позволит обращаться к внешней базе прямо из текста запроса 1С (через внешние источники данных), и тогда мы снова возвращаемся к Решению 1 — выполнению всей операции одним SQL-запросом.

Когда дублирование набора данных оправдано?

Дублирование набора данных (когда мы создаем "НаборДанных2_Вариант1" и "НаборДанных2_Вариант2") — это, как правило, "костыль". Это увеличивает потребление оперативной памяти и усложняет поддержку схемы. Однако это может быть оправдано в редких случаях, когда нам критически важно использовать разные настройки агрегации (разные ресурсы) для одних и тех же данных при разных условиях связи, и при этом объем данных невелик.

Подведем итоги

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

  1. Всегда старайтесь объединить данные в один запрос, используя несколько левых соединений с разными псевдонимами.
  2. Если запрос становится слишком громоздким, используйте пакетные запросы и временные таблицы внутри одного набора данных.
  3. Избегайте использования вкладки Связи наборов данных для соединения больших таблиц по параметрам, чтобы избежать лавинообразного роста количества запросов к БД.
  4. Если данные приходят извне, старайтесь максимально подготовить их до попадания в СКД или используйте средства интеграции на уровне СУБД.

Соблюдение этих правил позволит вашим отчетам работать мгновенно даже на больших объемах данных, обеспечивая комфортную работу пользователей.

← На главную