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

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

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

Зачем нужны временные таблицы?

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

Основные преимущества использования временных таблиц:

  1. Разбиение сложной логики: Мы можем разделить один «тяжелый» запрос на несколько простых и понятных этапов.
  2. Индексация промежуточных данных: Платформа позволяет создавать индексы по полям временных таблиц, что ускоряет последующие соединения.
  3. Повторное использование: Данные во временной таблице доступны на протяжении всего времени жизни менеджера временных таблиц.
  4. Улучшение планов запросов: СУБД гораздо проще работать с плоскими таблицами, чем с многоуровневыми вложениями.

Создание и использование менеджера временных таблиц

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

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


МенеджерВТ = Новый МенеджерВременныхТаблиц;
Запрос = Новый Запрос;
Запрос.МенеджерВременныхТаблиц = МенеджерВТ;

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

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

В данном примере ключевым словом является ПОМЕСТИТЬ. Именно оно дает команду платформе создать временную таблицу с именем ВТ_Товары. Обратите внимание, что после помещения данных в таблицу мы можем сразу же обращаться к ней в следующем пакете запроса (разделенном символом ;).

Оптимизация через индексацию

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

Для индексации используется ключевое слово ИНДЕКСИРОВАТЬ ПО. Разберем по шагам, как это добавить в запрос:


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

Здесь мы проиндексировали поле Номенклатура во временной таблице ВТ_Продажи. Это значительно ускорит выполнение левого соединения с виртуальной таблицей цен.

Передача временных таблиц между запросами

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

Для удаления конкретной временной таблицы в тексте запроса используется конструкция УНИЧТОЖИТЬ. Это полезная практика, если вы работаете с очень большими объемами данных и хотите освободить ресурсы до окончания выполнения всего кода.


ЗапросУничтожения = Новый Запрос;
ЗапросУничтожения.МенеджерВременныхТаблиц = МенеджерВТ;
ЗапросУничтожения.Текст = "УНИЧТОЖИТЬ ВТ_Товары";
ЗапросУничтожения.Выполнить();

Типичные ошибки при работе с временными таблицами

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

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

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

При работе с большими отчетами в 1С:ERP или 1С:Комплексная автоматизация, посмотрим на стратегию "разделяй и властвуй". Если ваш отчет собирает данные из нескольких регистров (например, остатки, продажи и заказы), лучше сначала поместить данные каждого регистра в свою временную таблицу, проиндексировать их по общим измерениям (Номенклатура, Склад), и только в финальном запросе объединить их.

Такой подход делает код 1С читаемым, а отладку — простой. Вы всегда можете извлечь содержимое любой временной таблицы для анализа в консоли запросов, просто заменив финальную выборку на ВЫБРАТЬ * ИЗ ВТ_НужнаяТаблица. Проанализировав вышесказанное, можно сделать вывод, что временные таблицы — это не просто вспомогательный инструмент, а основа высокопроизводительной разработки в среде 1С.

← На главную