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

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

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

Анализируем причины низкой производительности

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

РегистрНакопления.Взаиморасчеты...Остатки(&НачалоПериода, ДоговорКонтрагента.ВидДоговора В (&МассивВидовДоговоров)...)

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

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

Шаг 1: Оптимизация параметров виртуальных таблиц

Вместо того чтобы заставлять SQL-сервер «прыгать» по таблицам через точку, подготовим данные заранее. Мы воспользуемся временными таблицами для фильтрации. Рассмотрим, как это сделать правильно:


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

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

Такой подход позволяет платформе построить максимально эффективный SQL-запрос, используя только индексированные поля.

Шаг 2: Уход от множества наборов данных к «Остаткам и Оборотам»

Автор темы использовал 4 разных набора данных (Календарь, Основной, Начало, Конец). В СКД соединения между наборами данных выполняются на уровне прикладного сервера 1С, а не на уровне СУБД. Это означает, что данные сначала выкачиваются из базы в память, а потом «склеиваются». Если строк много, это приведет к перерасходу памяти и тормозам.

Выясним причину, почему автору не подошли стандартные механизмы. Часто это происходит из-за непонимания работы виртуальной таблицы ОстаткиИОбороты с периодичностью День. На самом деле, один запрос к этой таблице может заменить все четыре набора данных. Рассмотрим пример построения такого запроса:


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

Важный момент: Чтобы в отчете отображались дни, в которые не было движений (для динамики), не нужно использовать календарь. Достаточно в настройках СКД для поля ПериодДень установить «Дополнение периода». Это встроенный механизм СКД, который сам создаст строки для пустых дат, используя данные об остатках.

Шаг 3: Настройка ролей полей для корректного расчета итогов

Чтобы СКД понимала, как рассчитывать начальные и конечные остатки в группировках и за каждый день, мы должны зайти на закладку «Набор данных» и настроить Роли для ресурсов:

  1. Для поля ПериодДень: устанавливаем роль Период, порядковый номер 1. Это критически важно для работы дополнения дат.
  2. Для поля НачОстаток: роль Остатки, имя «Сумма», тип «Начальный остаток», поле периода «ПериодДень».
  3. Для поля КонОстаток: роль Остатки, имя «Сумма», тип «Конечный остаток», поле периода «ПериодДень».

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

Шаг 4: Оптимизация работы с датами документов

Как мы уже выяснили, обращение к ДокументРасчетовСКонтрагентом.Дата — это «красная тряпка» для производительности. Если нам нужно вычислить срок оплаты (ДатаДокумента + ДопустимоеЧислоДнейЗадолженности), лучше сделать это следующим образом:

Проанализируем ситуацию: если документов много, мы можем соединиться с индексированной таблицей ЖурналДокументов или использовать оператор ВЫРАЗИТЬ, если мы точно знаем типы документов. Но самый элегантный способ — получить дату документа в отдельной временной таблице еще до основного запроса:


ВЫБРАТЬ
    Документы.Ссылка КАК Ссылка,
    Документы.Дата КАК Дата
ПОМЕСТИТЬ ВТ_ДатыДокументов
ИЗ
    ЖурналДокументов.Взаиморасчеты КАК Документы // Используем подходящий журнал
ГДЕ
    Документы.Дата МЕЖДУ &НачалоДокументов И &КонецПериода;
ИНДЕКСИРОВАТЬ ПО Ссылка;

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

Альтернативное решение: Метод объединения (UNION)

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


// Таблица 1: Начальные остатки
ВЫБРАТЬ
    &НачалоПериода КАК Период,
    Организация, Контрагент, ДокументРасчетовСКонтрагентом,
    СуммаВзаиморасчетовОстаток КАК НачОстаток,
    0 КАК КонОстаток
ИЗ РегистрНакопления...Остатки(&НачалоПериода, ...)

ОБЪЕДИНИТЬ ВСЕ

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

ОБЪЕДИНИТЬ ВСЕ

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

Этот метод особенно хорош, когда нужно вывести детальную таблицу «Начальный остаток — Движение (Регистратор) — Конечный остаток» в рамках одной группировки колонок по дням. СКД сама схлопнет данные по измерениям, а благодаря полю Период правильно распределит их по оси времени.

Итоги и рекомендации

Для решения задачи по «тяжелому» отчету в СКД мы рекомендуем придерживаться следующего алгоритма:

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

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

← На главную