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

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

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

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

Когда мы используем вложенные запросы (особенно в секции ГДЕ или в соединениях), СУБД (MS SQL Server или PostgreSQL) не всегда может эффективно построить план выполнения. Вложенный запрос выполняется для каждой строки основного запроса, что приводит к квадратичной сложности. Рассмотрим подробнее: если во вложенном запросе 1000 строк и в основном 1000, общее количество итераций может достичь миллиона. Чтобы избежать этого, в 1С применяется механизм временных таблиц.

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

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

Сначала нам необходимо инициализировать объект и назначить его нашему запросу:


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

После этого мы можем помещать данные во временные таблицы с помощью конструкции ПОМЕСТИТЬ.

Создание и индексация временной таблицы

Просто создать временную таблицу недостаточно. Если мы планируем в дальнейшем соединять её с другими таблицами, нам крайне важно создать индексы. Без индексов СУБД будет выполнять полное сканирование (Table Scan) временной таблицы, что нивелирует все преимущества оптимизации. Посмотрим на пример эффективного создания временной таблицы с индексацией:


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

Запрос.Выполнить();

В данном примере мы использовали ключевое слово ИНДЕКСИРОВАТЬ ПО. Это заставляет систему создать индекс по полю Товар сразу после помещения данных в таблицу ВТ_ОстаткиТоваров.

Разделение сложных запросов на этапы

Одним из лучших практических советов является правило: "Один запрос — одна временная таблица". Если ваш запрос содержит более 3-4 соединений, его стоит разделить. Проанализируем ситуацию: СУБД проще оптимизировать несколько маленьких и понятных запросов, чем один огромный "портянку" с десятком левых соединений.

Давайте разберем, как выглядит структура сложного кода, разделенного на этапы:

  1. Этап 1: Сбор данных из регистров во временную таблицу ВТ_ДанныеРегистров с фильтрацией.
  2. Этап 2: Получение дополнительной информации из справочников и соединение с ВТ_ДанныеРегистров.
  3. Этап 3: Вывод итогового результата или помещение в финальную таблицу для отчета.

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

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

Особенности работы с временными таблицами в 1С 8.3

Важно помнить, что временные таблицы существуют до тех пор, пока жив объект МенеджерВременныхТаблиц или пока вы явно их не удалите. Выясним причину, по которой стоит удалять таблицы: если вы работаете с огромными массивами данных в цикле, накопление временных таблиц в tempdb на SQL-сервере может привести к переполнению дискового пространства.

Для удаления таблицы используйте ключевое слово УНИЧТОЖИТЬ в тексте запроса:


Запрос.Текст = "УНИЧТОЖИТЬ ВТ_ОстаткиТоваров";
Запрос.Выполнить();

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

При работе с запросами начинающие разработчики часто совершают ошибки, которые разберем подробнее:

Сравнение производительности: Практический пример

Посмотрим на пример: у нас есть задача получить продажи по клиентам, которые совершили покупки более чем на 100 000 рублей в прошлом месяце. Если мы напишем это одним запросом с вложенным подзапросом в ГДЕ, система сначала найдет всех клиентов, а потом для каждого будет проверять условие суммы. При использовании временной таблицы мы сначала один раз вычисляем список "крупных" клиентов, индексируем их ИД, и затем одним быстрым соединением получаем их продажи. На практике это дает прирост скорости в 5-10 раз на базе среднего размера.

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

← На главную