Как оптимизировать сложные запросы в 1С с помощью временных таблиц и индексации?

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

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

Проблема использования вложенных запросов

Проанализируем типичную ситуацию: когда мы используем вложенный запрос в конструкции ГДЕ Поле В (ВЫБРАТЬ ...), СУБД часто не может эффективно построить план выполнения. Это приводит к сканированию таблиц вместо использования индексов. Разберем по шагам, почему так происходит. При выполнении вложенного запроса система вынуждена выполнять его столько раз, сколько строк обрабатывается в основном запросе (в худшем случае), или создавать неявные временные объекты в оперативной памяти сервера SQL, которые не имеют индексов.

Для решения этой задачи мы будем использовать объект МенеджерВременныхТаблиц. Это специальный объект платформы, который позволяет хранить промежуточные результаты запроса в базе данных (в специально создаваемых временных таблицах SQL) и обращаться к ним в рамках одного сеанса работы с запросом.

Применение временных таблиц и пакетных запросов

Рассмотрим пример правильной структуры запроса. Вместо одного огромного текста с подзапросами, мы разделим логику на несколько этапов, используя пакетный запрос (несколько запросов, разделенных символом ";").

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


// Создаем менеджер временных таблиц для управления промежуточными данными
МенеджерВТ = Новый МенеджерВременныхТаблиц;
Запрос = Новый Запрос;
Запрос.МенеджерВременныхТаблиц = МенеджерВТ;

// Первый запрос пакета: выбираем данные во временную таблицу
Запрос.Текст = 
"ВЫБРАТЬ
|   РеализацияТоваровУслуг.Ссылка КАК СсылкаДокумента
|ПОМЕСТИТЬ ВТ_СписокДокументов
|ИЗ
|   Документ.РеализацияТоваровУслуг КАК РеализацияТоваровУслуг
|ГДЕ
|   РеализацияТоваровУслуг.Дата МЕЖДУ &ДатаНачала И &ДатаКонца
|ИНДЕКСИРОВАТЬ ПО
|   СсылкаДокумента
|;
|
|////////////////////////////////////////////////////////////////////////////////
|// ВТОРОЙ ЗАПРОС ПАКЕТА: используем данные из временной таблицы
|ВЫБРАТЬ
|   ВТ_СписокДокументов.СсылкаДокумента,
|   ПродажиОбороты.Номенклатура,
|   ПродажиОбороты.КоличествоОборот
|ИЗ
|   ВТ_СписокДокументов КАК ВТ_СписокДокументов
|       ВНУТРЕННЕЕ СОЕДИНЕНИЕ РегистрНакопления.Продажи.Обороты(,, Регистратор,) КАК ПродажиОбороты
|       ПО ВТ_СписокДокументов.СсылкаДокумента = ПродажиОбороты.Регистратор";

Запрос.УстановитьПараметр("ДатаНачала", НачалоДня(ТекущаяДата()));
Запрос.УстановитьПараметр("ДатаКонца", КонецДня(ТекущаяДата()));

Результат = Запрос.Выполнить();

Важность индексации временных таблиц

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

Работа с виртуальными таблицами

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

Рассмотрим подробнее работу с МенеджерВременныхТаблиц. Этот объект можно передавать между разными процедурами. Это позволяет нам подготовить данные в одном месте программы, а использовать — в другом. Не забывайте использовать метод Закрыть() для менеджера, когда работа с ним завершена, чтобы освободить ресурсы сервера, хотя платформа делает это автоматически при уничтожении объекта.

Основные рекомендации по повышению производительности

  1. Избегайте использования подзапросов в условии ИН: Всегда заменяйте их на временные таблицы с индексами.
  2. Ограничивайте выборку: В первом запросе пакета (при помещении в ВТ) выбирайте только те поля, которые действительно понадобятся в дальнейшем. Меньше данных — быстрее работа.
  3. Используйте типизацию: Если вы выбираете данные из неопределенных типов (например, поле Регистратор), старайтесь максимально сузить тип данных с помощью функции ВЫРАЗИТЬ.
  4. Следите за количеством временных таблиц: Слишком большое количество промежуточных таблиц (более 10-15) в одном пакете может запутать оптимизатор СУБД. Иногда лучше разбить один пакет на несколько последовательных вызовов.
  5. Проверяйте план запроса: Используйте консоль запросов с анализом плана выполнения, чтобы увидеть, действительно ли СУБД использует созданные вами индексы.

Выясним еще одну особенность: использование временных таблиц снижает вероятность блокировок базы данных. Поскольку данные подготавливаются заранее и считываются компактными порциями, транзакционная нагрузка распределяется более равномерно. Проанализируем пример, когда нужно получить остатки по списку товаров. Вместо того чтобы передавать массив из 1000 элементов прямо в параметр запроса Номенклатура В (&Массив), лучше загрузить этот массив во временную таблицу и соединиться с ней. Это предотвратит создание гигантских SQL-запросов, которые могут не пройти по ограничению длины строки в СУБД.

Заключение

Мы разобрали основы оптимизации через временные таблицы и пакетные запросы. Этот метод является "золотым стандартом" разработки на 1С 8.3. Использование ПОМЕСТИТЬ, ИНДЕКСИРОВАТЬ ПО и МенеджерВременныхТаблиц позволяет создавать масштабируемые и отказоустойчивые решения, которые будут работать быстро даже при значительном росте объема данных в информационной базе.

← На главную