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

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

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

Разберем проблему: почему запросы работают медленно?

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

Шаг 1: Использование параметров виртуальных таблиц

Первое правило оптимизации — всегда передавать условия фильтрации непосредственно в параметры виртуальной таблицы. Вместо использования секции ГДЕ, мы должны передать массив товаров или конкретный склад прямо в скобки РегистрНакопления.ТоварыНаСкладах.Остатки(&Период, Номенклатура В (&МассивНоменклатуры)). Это заставляет СУБД выбирать только нужные записи на самом раннем этапе выполнения.

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

Выясним причину, почему временные таблицы так важны. Если список номенклатуры очень велик, передача его через параметр В (&Массив) может создать гигантский SQL-запрос, который будет долго обрабатываться оптимизатором БД. Вместо этого мы создадим временную таблицу. Разберем по шагам, как это сделать программно.

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


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

Запрос.Текст = 
    "ВЫБРАТЬ
    |   СписокТоваров.Номенклатура КАК Номенклатура
    |ПОМЕСТИТЬ ВТ_НужныеТовары
    |ИЗ
    |   &ТаблицаТоваров КАК СписокТоваров";

Запрос.УстановитьПараметр("ТаблицаТоваров", ТЗ_СпискаТоваров);
Запрос.Выполнить();

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

Шаг 3: Обязательное индексирование временных таблиц

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

Добавим индексацию в наш текст запроса:


Запрос.Текст = 
    "ВЫБРАТЬ
    |   СписокТоваров.Номенклатура КАК Номенклатура
    |ПОМЕСТИТЬ ВТ_НужныеТовары
    |ИЗ
    |   &ТаблицаТоваров КАК СписокТоваров
    |ИНДЕКСИРОВАТЬ ПО
    |   Номенклатура";

Шаг 4: Соединение временной таблицы с виртуальными таблицами

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


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

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

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

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

Рассмотрим подробнее несколько практических советов, которые помогут вам писать более качественный код:

  1. Освобождение памяти: Если вы создали много временных таблиц в одном менеджере, не забывайте, что они занимают ресурсы. В конце работы можно вызвать метод МенеджерВТ.Закрыть(), чтобы явно очистить временные таблицы в СУБД.
  2. Пакетные запросы: Вместо нескольких вызовов метода Запрос.Выполнить(), старайтесь использовать пакетные запросы (разделяя тексты символом ";"). Это уменьшает количество обращений к серверу баз данных.
  3. Типизация полей: При помещении данных из таблицы значений во временную таблицу, убедитесь, что колонки таблицы значений типизированы. Если 1С не сможет определить тип поля, она создаст колонку неограниченной длины или типа ЛюбаяСсылка, что негативно скажется на производительности индекса.

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

← На главную