Как быстро получить дату последнего поступления товаров в 1С

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

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

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

Рассмотрим исходный вариант кода, который вызвал затруднения у автора темы. Основная проблема заключается в обращении к дате через регистратор: ПартииТоваровНаСкладахОстаткиИОбороты.Регистратор.Дата. Выясним причину, почему это плохо.

Поле Регистратор в регистрах накопления является составным типом данных. Оно может содержать ссылки на десятки различных документов: «Поступление товаров», «Перемещение», «Реализация», «Оприходование» и другие. Когда мы пишем в запросе Регистратор.Дата, платформа 1С на уровне СУБД выполняет левое соединение (LEFT JOIN) со всеми таблицами документов, которые могут выступать регистраторами для данного регистра. Если таких типов документов 30, SQL-запрос превращается в «монстра» с тридцатью соединениями, что критически замедляет выполнение, особенно при сканировании данных за несколько лет.

Решение 1: Использование функции ВЫРАЗИТЬ

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


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

В этом случае платформа понимает, что соединение нужно выполнить только с таблицей документа ПоступлениеТоваровУслуг, что значительно сокращает количество операций в СУБД.

Решение 2: Обращение к полю Период вместо Регистратор.Дата

Разберем еще более эффективный метод. В любом регистре накопления есть штатное поле Период. В 99% случаев в типовых конфигурациях Период записи в регистре совпадает с датой документа-регистратора. Обращение к полю Период происходит напрямую из таблицы регистра, без каких-либо соединений с таблицами документов.

Посмотрим на оптимизированную конструкцию:


МАКСИМУМ(ВЫБОР
    КОГДА ТоварыНаСкладахОстаткиИОбороты.Регистратор ССЫЛКА Документ.ПоступлениеТоваровУслуг
        ТОГДА ТоварыНаСкладахОстаткиИОбороты.Период
КОНЕЦ) КАК ДатаПоследнегоПоступления

Важный момент: Чтобы поле Период было доступно в виртуальной таблице ОстаткиИОбороты, необходимо в параметрах виртуальной таблицы указать периодичность Регистратор или Запись.

Решение 3: Использование физической таблицы регистра

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

  1. Выбираем данные из основной таблицы регистра (например, РегистрНакопления.ТоварыНаСкладах).
  2. Накладываем фильтр по виду движения Приход.
  3. Фильтруем по типу документа через ССЫЛКА.
  4. Используем группировку МАКСИМУМ(Период).

Пример кода для пакетного запроса:


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

Этот запрос отработает максимально быстро, так как поле Период и Номенклатура обычно входят в состав индексов таблицы регистра накопления.

Решение 4: Разделение запроса на пакеты (Временные таблицы)

Как мы видим из сообщения №23, автор пытался соединить в одном запросе остатки, обороты за период, резервы и цены. Такое полное соединение нескольких виртуальных таблиц порождает огромные временные таблицы в памяти сервера и крайне неоптимальные планы запросов.

Рассмотрим правильную стратегию построения сложного отчета:

  1. Шаг 1: Получаем список номенклатуры, которая нас интересует (например, те, по которым есть остатки или были обороты за период). Сохраняем их во временную таблицу ВТ_СписокНоменклатуры.
  2. Шаг 2: Отдельным запросом получаем даты последнего поступления, соединяя физическую таблицу регистра с нашей ВТ_СписокНоменклатуры.
  3. Шаг 3: Отдельным запросом получаем цены (СрезПоследних), также ограничивая выборку номенклатурой из ВТ_СписокНоменклатуры.
  4. Шаг 4: В финальном запросе соединяем все временные таблицы по полю Номенклатура.

Такой подход позволяет избежать проблем с неверными данными (как упоминалось в сообщении №24 относительно резервов) и гарантирует стабильную скорость работы отчета.

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

Выясним еще несколько хитростей, которые помогут ускорить работу:

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

← На главную