Как оптимизировать запрос 1С для поиска последнего документа поступления проданных товаров?

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

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

В чем причина низкой производительности исходного запроса?

Рассмотрим типичную ситуацию: запрос обращается напрямую к табличным частям Документ.РеализацияТоваровУслуг.Товары и Документ.ПоступлениеТоваровУслуг.Товары. Основная проблема здесь заключается в том, что табличные части документов в SQL-представлении не предназначены для массовой выборки и сложных соединений. При каждом обращении к ним сервер СУБД вынужден выполнять тяжелые операции чтения. Если в базе сотни тысяч строк, соединение «всех со всеми» по полю Номенклатура порождает гигантские временные таблицы в оперативной памяти.

Основные ошибки:

  1. Обращение к табличным частям вместо регистров накопления.
  2. Отсутствие индексов во временных таблицах.
  3. Соединение таблиц по неиндексированным полям.
  4. Избыточное количество данных, попадающих в выборку (отсутствие предварительных фильтров).

Шаг 1. Использование регистров накопления вместо документов

Первое, что мы должны сделать для ускорения работы — это отказаться от чтения табличных частей документов. В типовых конфигурациях 1С (УТ, ERP, КА, БП) данные о движениях товаров записываются в регистры накопления (например, Продажи, Закупки или ВыручкаИСебестоимость). Эти таблицы уже проиндексированы и оптимизированы для быстрого получения данных.

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

Шаг 2. Оптимизация получения данных о реализациях

Вместо того чтобы тянуть все данные из реализации сразу, мы выделим список реализованной номенклатуры в отдельную временную таблицу. При этом важно использовать ключевое слово РАЗЛИЧНЫЕ, чтобы сократить объем данных для последующих соединений.


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

Обратим внимание на конструкцию ИНДЕКСИРОВАТЬ ПО. Это критически важный момент. Без индекса последующее соединение этой таблицы с таблицей поступлений будет выполняться крайне медленно (методом полного сканирования).

Шаг 3. Поиск максимальной даты поступления

Теперь выясним причину, по которой поиск последнего прихода часто вызывает сложности. Если мы просто соединим реализации с поступлениями, мы получим все приходы по каждой позиции. Нам же нужен только один — последний. Для этого сначала получим таблицу максимальных дат для каждой номенклатуры.

Рассмотрим пример запроса для получения среза последних приходов:


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

Важное уточнение: В условии ГДЕ мы использовали фильтр Номенклатура В (ВЫБРАТЬ Номенклатура ИЗ ВТ_НоменклатураРеализаций). Это позволяет серверу SQL не перебирать все поступления в базе за все время, а ограничиться только теми товарами, которые были проданы в выбранном периоде.

Шаг 4. Обработка коллизий времени (МоментВремени)

В системе 1С возможна ситуация, когда несколько документов поступления созданы в одну и ту же секунду. Если мы будем искать только по полю Дата, запрос может вернуть несколько документов для одного товара. Чтобы этого избежать, профессиональные разработчики используют связку «Максимальная Дата + Максимальная Ссылка».

Разберем, как получить конкретную ссылку на последний документ:


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

Шаг 5. Сборка финального результата

Теперь, когда у нас есть временная таблица ВТ_ПоследниеСсылки, содержащая по одной уникальной ссылке на последнее поступление для каждой проданной позиции, мы можем собрать итоговый результат. Мы соединим данные реализации, номенклатуру и сведения из последнего поступления.


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

Дополнительные методы оптимизации

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

Итоги работы

Мы выяснили, что для оптимизации тяжелых запросов в 1С необходимо придерживаться строгой последовательности:

  1. Минимизировать выборку, отбирая только нужные поля и только за нужный период.
  2. Использовать временные таблицы для хранения промежуточных результатов.
  3. Обязательно индексировать временные таблицы по полям связи (обычно это Номенклатура или Ссылка).
  4. Избегать обращений через точку от полей табличных частей (например, Товары.Ссылка.Дата) внутри условий соединения, так как это порождает неявные JOIN в SQL.

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

← На главную