Как оптимизировать запросы в 1С 8.3 и значительно повысить скорость работы системы

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

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

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

Прежде чем приступать к исправлению кода, давайте проанализируем ситуацию и выясним, как 1С взаимодействует с СУБД (MS SQL Server, PostgreSQL и др.). Когда мы пишем запрос на языке 1С, платформа транслирует его в SQL-запрос. Если запрос составлен некорректно, СУБД не может эффективно использовать индексы, что приводит к полному сканированию таблиц (Table Scan). Это критически замедляет систему при росте объема данных.

Рассмотрим основные факторы, влияющие на производительность:

  1. Отсутствие индексов по полям, участвующим в условиях и соединениях.
  2. Использование вложенных запросов вместо временных таблиц.
  3. Неправильное обращение к виртуальным таблицам (остатки, обороты) без фильтрации по параметрам.
  4. Соединение с подзапросами или виртуальными таблицами.
  5. Использование конструкций ГДЕ для фильтрации данных виртуальных таблиц вместо использования параметров этих таблиц.

Использование временных таблиц: когда и зачем?

Одним из самых эффективных способов ускорения сложных запросов является использование объекта МенеджерВременныхТаблиц. Разберем по шагам, почему это работает лучше, чем вложенные запросы. Вложенный запрос выполняется СУБД динамически, и оптимизатору SQL бывает сложно построить эффективный план его выполнения. Временная таблица — это физическая таблица в базе данных (в tempdb), которую можно проиндексировать.

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


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

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

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

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

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

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

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

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

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

Рассмотрим подробнее пример кода:


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

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

Во втором варианте время выполнения запроса может сократиться в десятки раз, так как сервер БД будет обрабатывать только данные по конкретному складу, а не по всей компании сразу.

Оптимизация соединений и исключение разыменования через точку

Еще один важный аспект, который мы разберем — это обращение к полям через точку в тексте запроса (например, Продажи.Номенклатура.Артикул). Каждый раз, когда вы используете точку от ссылочного поля, 1С неявно добавляет ЛЕВОЕ СОЕДИНЕНИЕ со справочником в итоговый SQL-запрос. Если таких обращений много, количество соединений в запросе растет лавинообразно.

Выясним причину замедления на примере. Допустим, вам нужно получить Артикул и Группу номенклатуры. Вместо Продажи.Номенклатура.Артикул и Продажи.Номенклатура.Родитель, гораздо эффективнее один раз соединиться с таблицей справочника Номенклатура.

Давайте посмотрим на пример оптимизированного кода:


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

В данном случае мы явно контролируем процесс соединения. Это особенно важно, если вам нужно получить 5-10 реквизитов одного и того же объекта.

Практические советы по работе с индексами

Чтобы система работала быстро, необходимо понимать, какие поля должны быть проиндексированы. В 1С автоматически индексируются все стандартные поля (Ссылка, Дата, Код, Номер). Однако для дополнительных реквизитов, по которым часто происходит поиск или фильтрация, индекс нужно включать вручную в конфигураторе (свойство Индексировать).

Проанализируем рекомендации по индексации:

Борьба с блокировками данных

В высоконагруженных системах оптимизация запроса — это не только скорость, но и отсутствие блокировок. Если запрос выполняется долго, он может заблокировать таблицу, и другие пользователи не смогут проводить документы. Для уменьшения вероятности блокировок используйте:

  1. Минимально возможные выборки данных (не выбирайте *, указывайте только нужные поля).
  2. Разделение одного огромного запроса на несколько этапов с использованием временных таблиц.
  3. Использование разделения итогов для регистров накопления.

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

← На главную