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

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

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

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

Проанализируем типичную ситуацию: в исходном запросе автор пытается собрать данные о таможенных пошлинах, НДС и сборах из документа ГТДИмпорт, а также данные из ПоступлениеДопРасходовИмпорт. Основные ошибки, замедляющие выполнение, включают:

  1. Многократное обращение к одной и той же таблице: Для получения разных видов сумм (пошлина, НДС, сбор) используются три отдельных блока ОБЪЕДИНИТЬ ВСЕ, каждый из которых заново читает таблицу Документ.ГТДИмпорт.Товары.
  2. Вложенные запросы: СУБД сложно строить оптимальный план выполнения, когда соединения происходят не с физическими таблицами, а с результатами других подзапросов.
  3. Обращение через точку (разыменование): Пути типа Ссылка.ДоговорВзаиморасчетов.ВалютаВзаиморасчетов порождают неявные LEFT JOIN в SQL-запросе, что кратно увеличивает нагрузку.
  4. Строковые операции: Конкатенация строк типа "ДР: " + Содержание внутри запроса мешает кэшированию и замедляет обработку.

Шаг 1: Оптимизация обращений к таблице ГТД

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


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

Обратите внимание: мы сразу сгруппировали данные. Это уменьшит количество записей, которые будут переданы в следующие этапы запроса.

Шаг 2: Использование временных таблиц и индексация

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

Рассмотрим, как подготовить данные из заказа поставщика, также используя временную таблицу:


ВЫБРАТЬ
    ЗаказТовары.Номенклатура КАК Номенклатура,
    СУММА(ЗаказТовары.Количество) КАК КоличествоЗаказа
ПОМЕСТИТЬ ВТ_Заказ
ИЗ
    Документ.ЗаказПоставщикуОтгруженный.Товары КАК ЗаказТовары
ГДЕ
    ЗаказТовары.Ссылка = &Основание
СГРУППИРОВАТЬ ПО
    ЗаказТовары.Номенклатура
ИНДЕКСИРОВАТЬ ПО
    Номенклатура
;

Шаг 3: Объединение данных и избавление от "точек"

Теперь разберем ситуацию с "разыменованием" полей. Вместо обращения ГТДИмпортТовары.Ссылка.ДоговорВзаиморасчетов.ВалютаВзаиморасчетов, лучше один раз соединиться с таблицей договора. Также на этом этапе мы "развернем" наши суммы из ГТД обратно в строки, но уже работая с маленькой временной таблицей в памяти, а не с огромной таблицей документов.

Проанализируем итоговую сборку данных:


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

Шаг 4: Оптимизация группировок и строковых полей

Выясним причину, по которой группировка может работать медленно. Группировка по длинным строковым полям (таким как Содержание) — очень дорогая операция. Если есть возможность, рекомендуется:

Итоговые рекомендации по оптимизации

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

  1. Никогда не используйте вложенные запросы в соединении. Всегда выносите их во временные таблицы (ВТ).
  2. Индексируйте поля связи во временных таблицах. Это позволяет СУБД использовать Index Seek вместо полного сканирования таблицы.
  3. Сокращайте количество обращений к физическим таблицам. Если данные нужны из одной таблицы несколько раз, выберите их один раз в ВТ, а затем манипулируйте данными ВТ.
  4. Избегайте обращений через точку. Каждая точка от ссылочного поля — это скрытое соединение, которое может замедлить запрос, если оно находится внутри цикла или сложной выборки.
  5. Фильтруйте данные как можно раньше. Используйте параметры &Основание и &МассивНоменклатуры в самых первых запросах пакета, чтобы в ВТ попадал минимально необходимый объем данных.

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

← На главную