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

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

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

Разберем причины низкой производительности

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

Проанализируем использование индексов

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

Если мы напишем условие следующим образом:


ГДЕ
    НАЧАЛОПЕРИОДА(РегистрПродаж.Период, ДЕНЬ) = &НужнаяДата

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


ГДЕ
    РегистрПродаж.Период МЕЖДУ &НачалоДня И &КонецДня

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

Виртуальные таблицы, такие как ОстаткиИОбороты или СрезПоследних, являются мощным инструментом 1С, но их неправильное использование часто становится узким местом. Разберем золотое правило: всегда накладывайте отборы в параметрах виртуальной таблицы, а не в секции ГДЕ.

Рассмотрим пример неэффективного запроса:


ВЫБРАТЬ
    ПродажиОбороты.Номенклатура,
    ПродажиОбороты.КоличествоОборот
ИЗ
    РегистрНакопления.Продажи.Обороты КАК ПродажиОбороты
ГДЕ
    ПродажиОбороты.Номенклатура = &ВыбраннаяНоменклатура

В этом случае платформа сначала получит обороты по всем товарам за указанный период, а затем отфильтрует их. Правильным подходом будет передача отбора непосредственно в параметры:


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

Такой подход позволяет СУБД выбрать только нужные записи на самом раннем этапе выполнения запроса.

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

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

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

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

Пример кода на встроенном языке:


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

Запрос.УстановитьПараметр("Начало", НачалоДня(ДатаОтчета));
Запрос.УстановитьПараметр("Конец", КонецДня(ДатаОтчета));
Результат = Запрос.Выполнить();

Проанализируем типичные ошибки при соединениях

При использовании левых соединений важно помнить о порядке таблиц и условиях. Рассмотрим важные моменты:

Например, использование ВЫРАЗИТЬ для полей составного типа позволяет системе более точно определить таблицу для соединения на уровне СУБД:


ПО
    ВТ_Данные.ДокументОснование = ВЫРАЗИТЬ(Регистр.Документ КАК Документ.РеализацияТоваровУслуг)

Выводы и рекомендации

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

← На главную