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

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

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

Анализ проблемы: почему запрос тормозит

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

1. Использование параметров виртуальных таблиц вместо секции ГДЕ

Это классическая ошибка. Проанализируем фрагмент запроса:


ИЗ РегистрНакопления.ТоварыНаСкладах.ОстаткиИОбороты(, &СегодняшняяДата, Авто, , ) КАК ТоварыНаСкладахОстаткиИОбороты
...
ГДЕ ТоварыНаСкладахОстаткиИОбороты.Качество = &Качество И ТоварыНаСкладахОстаткиИОбороты.Склад = &Склад

Когда условие отбора (например, по складу или качеству) стоит в секции ГДЕ, система сначала выбирает все остатки и обороты по всем складам организации из базы данных, и только потом фильтрует их в памяти сервера 1С. Чтобы оптимизировать этот узел, необходимо передавать условия напрямую в параметры виртуальной таблицы.

Как сделать правильно: передадим параметры в первую скобку виртуальной таблицы. Это позволит СУБД выполнить фильтрацию еще на этапе чтения данных с диска.


ИЗ РегистрНакопления.ТоварыНаСкладах.ОстаткиИОбороты(, &СегодняшняяДата, Авто, , Склад = &Склад И Качество = &Качество) КАК ТоварыНаСкладахОстаткиИОбороты

2. Проблема неявных соединений (обращение «через точку»)

В тексте часто встречается конструкция ЗаказПокупателяТовары.Ссылка.ДатаОтгрузки. На уровне SQL это приводит к неявному левому соединению (LEFT JOIN) таблицы табличной части с таблицей шапки документа. Если в базе сотни тысяч строк в заказах, это создает колоссальную нагрузку.

Рассмотрим, как это оптимизировать:

  1. Сначала выберем ссылки на нужные документы во временную таблицу, отфильтровав их по дате и статусу.
  2. Затем соединим эту временную таблицу с табличной частью товаров.

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

3. Оптимизация оператора В ИЕРАРХИИ

Оператор В ИЕРАРХИИ — один из самых ресурсоемких. В SQL он разворачивается в сложную структуру с подзапросами. Если вы используете его несколько раз в разных частях пакета запросов, производительность будет падать лавинообразно.

Рекомендуемый подход:

4. Индексация временных таблиц

Когда мы создаем временные таблицы (например, ВТ_Номенклатура или Номенклатура_ВЗаказах) и в дальнейшем используем их в соединениях по полю Номенклатура, система должна быстро находить соответствующие записи. Без индекса СУБД будет выполнять полный перебор таблицы при каждом соединении.

Важное правило: индексируйте поля временных таблиц, по которым идет связь (ПО) или условие. В конструкторе запросов это делается на закладке "Индексы".


ВЫБРАТЬ Номенклатура.Ссылка КАК Номенклатура 
ПОМЕСТИТЬ ВТ_Номенклатура 
ИЗ Справочник.Номенклатура КАК Номенклатура 
ГДЕ Номенклатура.Ссылка В ИЕРАРХИИ(&ГруппаНоменклатуры)
ИНДЕКСИРОВАТЬ ПО Номенклатура;

5. Превращение Левого соединения во Внутреннее

Обратим внимание на финальное соединение. Если вы используете ЛЕВОЕ СОЕДИНЕНИЕ, но в секции ГДЕ ставите условие на поле из "правой" таблицы, соединение фактически превращается во ВНУТРЕННЕЕ. Это происходит потому, что для отсутствующих записей поля будут иметь значение NULL, а сравнение NULL = &Параметр всегда ложно.

Чтобы сохранить логику левого соединения и не терять данные, условия по правой таблице (например, склад или качество) нужно переносить либо в параметры виртуальной таблицы, либо непосредственно в условие связи ПО.

6. Выбор между Остатки и ОстаткиИОбороты

В запросе часто используется таблица ОстаткиИОбороты, хотя фактически разработчику нужен только КонечныйОстаток. Виртуальная таблица ОстаткиИОбороты самая "тяжелая", так как она рассчитывает итоги и движения одновременно.

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

7. Избыточность кода и мусорные выражения

Иногда в запросах встречаются конструкции типа ЕСТЬNULL(0, 0) или 0 КАК Поле1, которые остаются после отладки или планируются "на будущее". Несмотря на то, что современные оптимизаторы SQL могут их игнорировать, они усложняют чтение запроса и построение плана выполнения. Проанализируем ситуацию: лучше сразу передавать готовые данные или использовать расчет внутри запроса без лишних вложенных ЕСТЬNULL.

Разберем пример очистки выражения:

Вместо: ЕСТЬNULL(Поле1, 0) - ЕСТЬNULL(Поле2, 0) + ЕСТЬNULL(0, 0)

Используем: ЕСТЬNULL(Поле1, 0) - ЕСТЬNULL(Поле2, 0)

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

  1. Минимизируем выборку: не выбирайте весь справочник номенклатуры, если вам нужны данные только по товарам из конкретного документа.
  2. Используем параметры ВТ: склад, период, качество и номенклатуру передавайте в параметры виртуальных таблиц.
  3. Индексируем ВТ: все временные таблицы, которые участвуют в соединениях, должны иметь индексы по ключевым полям.
  4. Упрощаем связи: избавляйтесь от обращений через точку к полям ссылочных типов в условиях.
  5. Инструменты отладки: используйте консоль запросов с замером времени или "Инструменты разработчика" для анализа плана выполнения SQL. Это позволит увидеть, какой именно подзапрос занимает 90% времени.

Применяя эти правила, можно добиться стабильной и быстрой работы даже самых сложных отчетов в 1С.

← На главную