В процессе разработки отчетов в 1С программисты часто сталкиваются с задачей получения даты последней закупки для номенклатуры. Когда данных немного, задача решается простым запросом, но если база содержит информацию за 5–10 лет, стандартные методы начинают работать крайне медленно. В этой статье мы проанализируем ситуацию, разберем типичные ошибки и рассмотрим несколько способов оптимизации, которые позволяют ускорить получение данных в разы.
Рассмотрим исходный вариант кода, который вызвал затруднения у автора темы. Основная проблема заключается в обращении к дате через регистратор: ПартииТоваровНаСкладахОстаткиИОбороты.Регистратор.Дата. Выясним причину, почему это плохо.
Поле Регистратор в регистрах накопления является составным типом данных. Оно может содержать ссылки на десятки различных документов: «Поступление товаров», «Перемещение», «Реализация», «Оприходование» и другие. Когда мы пишем в запросе Регистратор.Дата, платформа 1С на уровне СУБД выполняет левое соединение (LEFT JOIN) со всеми таблицами документов, которые могут выступать регистраторами для данного регистра. Если таких типов документов 30, SQL-запрос превращается в «монстра» с тридцатью соединениями, что критически замедляет выполнение, особенно при сканировании данных за несколько лет.
Если нам нужно получить дату конкретного типа документа (например, только поступлений), мы должны явно указать платформе, к какой таблице обращаться. Это делается с помощью функции ВЫРАЗИТЬ. Проанализируем пример кода:
МАКСИМУМ(ВЫБОР
КОГДА ПартииТоваровНаСкладахОстаткиИОбороты.Регистратор ССЫЛКА Документ.ПоступлениеТоваровУслуг
ТОГДА ВЫРАЗИТЬ(ПартииТоваровНаСкладахОстаткиИОбороты.Регистратор КАК Документ.ПоступлениеТоваровУслуг).Дата
КОНЕЦ) КАК ДатаПоследнегоПоступления
В этом случае платформа понимает, что соединение нужно выполнить только с таблицей документа ПоступлениеТоваровУслуг, что значительно сокращает количество операций в СУБД.
Разберем еще более эффективный метод. В любом регистре накопления есть штатное поле Период. В 99% случаев в типовых конфигурациях Период записи в регистре совпадает с датой документа-регистратора. Обращение к полю Период происходит напрямую из таблицы регистра, без каких-либо соединений с таблицами документов.
Посмотрим на оптимизированную конструкцию:
МАКСИМУМ(ВЫБОР
КОГДА ТоварыНаСкладахОстаткиИОбороты.Регистратор ССЫЛКА Документ.ПоступлениеТоваровУслуг
ТОГДА ТоварыНаСкладахОстаткиИОбороты.Период
КОНЕЦ) КАК ДатаПоследнегоПоступления
Важный момент: Чтобы поле Период было доступно в виртуальной таблице ОстаткиИОбороты, необходимо в параметрах виртуальной таблицы указать периодичность Регистратор или Запись.
Виртуальные таблицы (например, ОстаткиИОбороты) удобны, но они заставляют систему выполнять дополнительные расчеты итогов. Если наша задача — просто найти дату последнего прихода, гораздо быстрее будет обратиться к физической таблице регистра. Рассмотрим, как это сделать правильно:
РегистрНакопления.ТоварыНаСкладах).Приход.ССЫЛКА.МАКСИМУМ(Период).Пример кода для пакетного запроса:
ВЫБРАТЬ
ТоварыНаСкладах.Номенклатура КАК Номенклатура,
МАКСИМУМ(ТоварыНаСкладах.Период) КАК ДатаПоследнегоПрихода
ПОМЕСТИТЬ ВТ_ПоследниеДаты
ИЗ
РегистрНакопления.ТоварыНаСкладах КАК ТоварыНаСкладах
ГДЕ
ТоварыНаСкладах.ВидДвижения = ЗНАЧЕНИЕ(ВидДвиженияНакопления.Приход)
И ТоварыНаСкладах.Регистратор ССЫЛКА Документ.ПоступлениеТоваровУслуг
И ТоварыНаСкладах.Активность = ИСТИНА
СГРУППИРОВАТЬ ПО
ТоварыНаСкладах.Номенклатура
;
Этот запрос отработает максимально быстро, так как поле Период и Номенклатура обычно входят в состав индексов таблицы регистра накопления.
Как мы видим из сообщения №23, автор пытался соединить в одном запросе остатки, обороты за период, резервы и цены. Такое полное соединение нескольких виртуальных таблиц порождает огромные временные таблицы в памяти сервера и крайне неоптимальные планы запросов.
Рассмотрим правильную стратегию построения сложного отчета:
ВТ_СписокНоменклатуры.ВТ_СписокНоменклатуры.ВТ_СписокНоменклатуры.Номенклатура.Такой подход позволяет избежать проблем с неверными данными (как упоминалось в сообщении №24 относительно резервов) и гарантирует стабильную скорость работы отчета.
Выясним еще несколько хитростей, которые помогут ускорить работу:
Номенклатура.МАКСИМУМ(Период) все равно остается самым надежным.Номенклатура.Артикул. Лучше заранее выбрать артикулы во временную таблицу или соединить финальный результат со справочником номенклатуры один раз. Каждая «точка» в условии ГДЕ или СГРУППИРОВАТЬ ПО — это скрытое соединение таблиц.Подводя итог, можно сказать: для получения даты последнего поступления за большой период забудьте про Регистратор.Дата и виртуальные таблицы ОстаткиИОбороты без крайней необходимости. Используйте физические таблицы, поле Период и пакетные запросы — это профессиональный стандарт разработки на платформе 1С.