Как объединить три запроса в один при работе с регистрами накопления в 1С

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

В практике разработки на платформе 1С:Предприятие часто возникает ситуация, когда необходимо получить данные из одного регистра, но с разной логикой обработки для разных типов документов. Начинающие разработчики часто используют конструкцию ОБЪЕДИНИТЬ ВСЕ (UNION ALL), что приводит к избыточным обращениям к базе данных и падению производительности. В этой статье мы разберем, как свести три запроса в один эффективный, оптимизировать работу с виртуальными таблицами и правильно настроить сортировку данных.

Анализ исходной проблемы

Рассмотрим ситуацию: нам нужно получить отчет по движениям товаров на складе в суммовом выражении. Сложность заключается в том, что разные документы формируют суммы по-разному. Например, в документе ПеремещениеТоваров сумма может быть как приходом, так и расходом в зависимости от склада, а в документе апт_ПереоценкаТоваровНаСкладе используются специфические поля СуммаДокумента и СуммаДокументаПоНовойЦене.

Изначальный подход с использованием ОБЪЕДИНИТЬ ВСЕ заставляет систему выполнять три полноценных сканирования таблиц. Проанализируем, как сделать это за один проход.

Решение №1: Использование конструкции ВЫБОР КОГДА вместо объединения

Самый эффективный способ объединить логику — перенести условия внутрь полей выборки. Вместо того чтобы фильтровать типы документов в секции ГДЕ для каждого подзапроса, мы опишем правила распределения сумм в одном списке полей. Разберем этот метод по шагам.

Воспользуемся оператором ССЫЛКА для определения типа документа-регистратора и функцией ВЫБОР КОГДА для вычисления прихода и расхода. Проанализируем пример кода:


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

В данном случае мы обращаемся к физической таблице регистра накопления. Это значительно быстрее, чем использование виртуальной таблицы ОстаткиИОбороты, если нам не нужны начальные и конечные остатки на каждую дату.

Решение №2: Оптимизация обращений через точку

Важно помнить, что обращение Регистратор.СуммаДокумента — это неявное соединение (LEFT JOIN) со всеми таблицами документов, которые могут быть регистраторами. Если их в системе много, SQL-запрос будет перегружен. Чтобы избежать этого, рассмотрим более профессиональный подход с использованием временных таблиц.

  1. Сначала выберем все ссылки на нужные регистраторы во временную таблицу.
  2. Проиндексируем их по полю Регистратор.
  3. Соединим временную таблицу с конкретными таблицами документов (например, только с таблицей «Поступление товаров» или «Перемещение»).

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

Проблема сортировки по дате и моменту времени

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

Рассмотрим правильный способ упорядочивания:

Автоупорядочивание: Использование ключевого слова АВТОУПОРЯДОЧИВАНИЕ в конце запроса заставляет систему сортировать данные по «моменту времени» (дата + ссылка). Это гарантирует стабильный результат.


УПОРЯДОЧИТЬ ПО
    Регистратор АВТОУПОРЯДОЧИВАНИЕ

Если же мы хотим сортировать по дате без явного выбора поля Дата в итоговый результат (хотя это редко требуется), мы все равно можем использовать поле Период в секции УПОРЯДОЧИТЬ ПО, так как оно является индексированным в таблицах регистров.

Выбор между виртуальной и физической таблицей

Проанализируем ситуацию, описанную в сообщениях форума. Автор использует ОстаткиИОбороты. Если задача — получить только список документов и суммы из них, использование виртуальной таблицы — это «стрельба из пушки по воробьям». Система тратит ресурсы на расчет итогов, которые потом не используются.

Рекомендация: Если вам нужны только обороты в разрезе регистратора, используйте таблицу Движения (или просто основную таблицу регистра). В ней уже есть поле ВидДвижения, которое автоматически разделяет записи на Приход и Расход, что позволяет еще сильнее упростить условия ВЫБОР КОГДА.

Итоговый алгоритм оптимизации запроса

Подведем итог и составим пошаговый план для приведения запроса к идеальному виду:

  1. Отказываемся от UNION ALL: Объединяем все условия в одну выборку, используя ВЫБОР КОГДА.
  2. Уточняем источник данных: Если остатки на начало и конец не нужны, заменяем ОстаткиИОбороты на физическую таблицу регистра.
  3. Фильтруем типы: В секции ГДЕ обязательно ограничиваем выборку типами регистраторов (используя ССЫЛКА), чтобы исключить лишние данные.
  4. Настраиваем сортировку: Используем УПОРЯДОЧИТЬ ПО Период, Регистратор или АВТОУПОРЯДОЧИВАНИЕ.
  5. Минимизируем обращения через точку: Если производительность все еще низкая, выносим получение реквизитов документов (Сумма, СкладОтправитель) в отдельные соединения через временные таблицы.

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

← На главную