Почему запрос по остаткам номенклатуры в 1С:Розница 2.3 работает медленно и как это исправить?

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

В процессе разработки отчетов в 1С:Розница 2.3 программисты часто сталкиваются с необъяснимым, на первый взгляд, поведением системы: один и тот же запрос за разные периоды выполняется с колоссальной разницей во времени. Ситуация, когда расчет за декабрь занимает минуту, а за январь — пятнадцать, при этом повторный запуск "лечит" проблему, является классическим симптомом для файловых баз данных. Рассмотрим подробно, почему это происходит и как оптимизировать код запроса.

Разбор архитектурной проблемы: Холодный и горячий старт

Проанализируем ситуацию, когда после перезагрузки базы или при первом обращении к данным за новый период запрос "зависает". Основная причина здесь кроется в механизмах кэширования операционной системы и самой платформы 1С. Файловая СУБД 1С (файл .1CD) очень сильно зависит от дисковых операций чтения. При первом выполнении запроса ("холодный старт") системе необходимо физически вычитать данные с диска, просканировать индексы и загрузить их в оперативную память (системный кэш Windows).

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

Также стоит учитывать влияние антивирусного ПО. При активном обращении к большому файлу базы данных антивирус может начать его сканирование "на лету", что создает дополнительную нагрузку на дисковую подсистему и замедляет чтение данных в разы.

Влияние даты на выборку из итогов

Выясним причину, по которой выбор периода (начало или конец месяца) критически влияет на скорость. В 1С:Предприятие итоги хранятся в специальных таблицах на начало каждого месяца (00:00:00 первого числа). Рассмотрим, как работает виртуальная таблица Остатки:

  1. Если вы запрашиваете остатки на 01.01.2021 00:00:00, платформа просто берет готовые цифры из таблицы итогов. Это происходит мгновенно.
  2. Если вы запрашиваете остатки на 31.01.2021 23:59:59, платформе необходимо взять итоги на 01.02.2021 и вычесть из них все движения, совершенные за январь, либо взять итоги на 01.01.2021 и прибавить движения января. В любом случае, происходит сканирование основной таблицы движений регистра, что при большом количестве документов занимает много времени.

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

Анализ и оптимизация текста запроса

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


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

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

Рассмотрим вторую часть — получение остатков:


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

Здесь допущена главная ошибка производительности — обращение через точку в параметрах виртуальной таблицы. Условие Номенклатура.Родитель <> ... внутри скобок Остатки() заставляет 1С выполнять неявное соединение таблиц регистра и справочника для каждой записи в процессе расчета итогов. В файловом режиме это превращает запрос в крайне медленный процесс.

Рекомендуемый способ оптимизации

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

  1. Сначала получим только те ссылки номенклатуры, по которым вообще есть остатки.
  2. Затем соединим этот короткий список со справочником для получения иерархии.
  3. Обязательно проиндексируем временные таблицы по полям соединения.

Проанализируем оптимизированный вариант запроса:


// Шаг 1: Получаем остатки без лишних условий "через точку"
ВЫБРАТЬ
    ТоварыОстатки.Номенклатура КАК Номенклатура,
    ТоварыОстатки.КоличествоОстаток КАК Количество
ПОМЕСТИТЬ ВТ_Остатки
ИЗ
    РегистрНакопления.ТоварыНаСкладах.Остатки(&Дата, ) КАК ТоварыОстатки
ИНДЕКСИРОВАТЬ ПО
    Номенклатура
;

// Шаг 2: Формируем итоговый результат
ВЫБРАТЬ
    Номенклатура.Родитель КАК Родитель,
    СУММА(ВЫБОР КОГДА ВТ_Остатки.Количество ЕСТЬ NULL ТОГДА 0 ИНАЧЕ 1 КОНЕЦ) КАК ВНаличии,
    СУММА(1) КАК Всего
ИЗ
    Справочник.Номенклатура КАК Номенклатура
    ЛЕВОЕ СОЕДИНЕНИЕ ВТ_Остатки КАК ВТ_Остатки
    ПО Номенклатура.Ссылка = ВТ_Остатки.Номенклатура
ГДЕ
    НЕ Номенклатура.ЭтоГруппа
    И Номенклатура.Родитель <> ЗНАЧЕНИЕ(Справочник.Номенклатура.ПустаяСсылка)
СГРУППИРОВАТЬ ПО
    Номенклатура.Родитель

В данном примере мы исключили ресурсоемкие операции внутри виртуальной таблицы. Использование ИНДЕКСИРОВАТЬ ПО для временной таблицы ВТ_Остатки позволяет ЛЕВОМУ СОЕДИНЕНИЮ отработать максимально быстро. Также обратите внимание, что мы проверяем условие НЕ Номенклатура.ЭтоГруппа, чтобы считать только элементы, а не сами папки справочника.

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

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

Таким образом, мы выяснили, что "магия" ускорения запроса после повторного запуска — это всего лишь работа дискового кэша, а длительное выполнение — следствие неоптимальных фильтров в параметрах виртуальных таблиц и специфики хранения итогов в 1С.

← На главную