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

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

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

Почему вложенные запросы замедляют систему?

Проанализируем ситуацию: когда СУБД встречает вложенный запрос в секции ГДЕ или в соединении, она зачастую вынуждена выполнять его многократно или создавать неоптимальные промежуточные структуры в оперативной памяти. Это приводит к росту нагрузки на процессор и дисковую подсистему сервера. Рассмотрим альтернативу — временные таблицы. Использование временных таблиц позволяет нам «разрезать» сложный алгоритм на простые шаги, каждый из которых СУБД выполняет максимально быстро.

Шаг 1: Использование конструкции ПОМЕСТИТЬ

Первым делом разберем, как создать временную таблицу внутри текста запроса. Для этого используется ключевое слово ПОМЕСТИТЬ. Посмотрим на пример кода, где мы сначала выбираем данные из справочника, сохраняем их во временную таблицу, а затем используем их в основном запросе.


Запрос = Новый Запрос;
Запрос.Текст = 
"ВЫБРАТЬ
|	Номенклатура.Ссылка КАК Товар,
|	Номенклатура.Код КАК Код
|ПОМЕСТИТЬ ВТ_Товары
|ИЗ
|	Справочник.Номенклатура КАК Номенклатура
|ГДЕ
|	Номенклатура.Услуга = ЛОЖЬ
|;
|
|////////////////////////////////////////////////////////////////////////////////
|ВЫБРАТЬ
|	ВТ_Товары.Товар,
|	ВТ_Товары.Код,
|	ЦеныНоменклатурыСрезПоследних.Цена
|ИЗ
|	ВТ_Товары КАК ВТ_Товары
|		ЛЕВОЕ СОЕДИНЕНИЕ РегистрСведений.ЦеныНоменклатуры.СрезПоследних КАК ЦеныНоменклатурыСрезПоследних
|		ПО ВТ_Товары.Товар = ЦеныНоменклатурыСрезПоследних.Номенклатура";

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

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

Шаг 2: Индексация временных таблиц — ключ к успеху

Просто поместить данные во временную таблицу недостаточно для максимальной производительности. Если временная таблица содержит более нескольких сотен строк, СУБД будет выполнять «полное сканирование» (Full Scan) при каждом соединении. Чтобы этого избежать, нам необходимо индексировать поля, по которым происходит соединение. Рассмотрим, как это сделать с помощью ключевого слова ИНДЕКСИРОВАТЬ ПО.


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

Выясним причину ускорения: благодаря инструкции ИНДЕКСИРОВАТЬ ПО, система создает во временной базе данных (TempDB) индекс. Теперь при выполнении ВНУТРЕННЕЕ СОЕДИНЕНИЕ СУБД мгновенно находит нужные записи, не перебирая всю таблицу ВТ_Продажи целиком.

Шаг 3: Работа с объектом МенеджерВременныхТаблиц

Иногда требуется использовать одну и ту же временную таблицу в разных объектах Запрос в рамках одного сеанса или одной процедуры. В этом случае нам поможет МенеджерВременныхТаблиц. Рассмотрим подробнее, как организовать совместную работу нескольких запросов.


// Создаем менеджер
МенеджерВТ = Новый МенеджерВременныхТаблиц;

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

// Теперь данные хранятся в МенеджерВТ и доступны для других запросов
Запрос2 = Новый Запрос;
Запрос2.МенеджерВременныхТаблиц = МенеджерВТ;
Запрос2.Текст = 
"ВЫБРАТЬ
|	ВТ_Объекты.Ссылка
|ИЗ
|	ВТ_Объекты КАК ВТ_Объекты";

Выборка = Запрос2.Выполнить().Выбрать();
Пока Выборка.Следующий() Цикл
	// Обработка данных
КонецЦикла;

// После завершения работы менеджер желательно закрыть для освобождения памяти
МенеджерВТ.Закрыть();

Важно помнить, что МенеджерВременныхТаблиц занимает место в оперативной памяти и TempDB на сервере. Если вы создаете очень большие таблицы, не забывайте вызывать метод Закрыть() или удалять временные таблицы вручную с помощью команды УНИЧТОЖИТЬ в тексте запроса.

Практические советы и правила работы

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

  1. Не используйте временные таблицы для 5-10 строк. Если данных совсем мало, накладные расходы на создание таблицы и запись в TempDB могут превысить выгоду от оптимизации.
  2. Всегда индексируйте поля соединений. Если вы планируете использовать временную таблицу в JOIN с другой таблицей, индекс по полю связи обязателен.
  3. Следите за типами данных. Если в одном запросе вы помещаете в колонку тип Число, а в другом пытаетесь соединить его со строкой, возникнет ошибка или резкое замедление.
  4. Разделяйте выборку и расчет. Сначала соберите все необходимые данные во временные таблицы (подготовьте «сырье»), а финальным запросом выполните все математические операции и группировки.
  5. Используйте виртуальные таблицы правильно. Старайтесь не помещать виртуальные таблицы (типа ОстаткиИОбороты) целиком во временную таблицу без предварительной фильтрации по параметрам Период или Условие.

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

← На главную