При разработке сложных отчетов или обработок в системе 1С:Предприятие программисты часто сталкиваются с проблемой низкой производительности запросов. Одной из основных причин замедления является использование вложенных запросов в соединениях или работа с большими объемами данных в виртуальных таблицах без предварительной подготовки. В данной статье мы подробно разберем, как использование временных таблиц помогает оптимизировать работу системы и какие инструменты для этого предоставляет платформа.
Когда мы используем вложенный запрос в секции ЛЕВОЕ СОЕДИНЕНИЕ или ГДЕ, планировщик запросов СУБД (будь то MS SQL Server или PostgreSQL) не всегда может эффективно определить статистику распределения данных. В результате создается неоптимальный план выполнения, что приводит к сканированию всей таблицы вместо поиска по индексу. Рассмотрим ситуацию: нам нужно получить остатки товаров только по списку определенных номенклатурных позиций, которые удовлетворяют сложному условию.
Проанализируем типичный пример «плохого» кода:
ВЫБРАТЬ
Продажи.Номенклатура,
Продажи.КоличествоОборот
ИЗ
РегистрНакопления.Продажи.Обороты(&НачалоПериода, &КонецПериода) КАК Продажи
ГДЕ
Продажи.Номенклатура В (
ВЫБРАТЬ
Номенклатура
ИЗ
Справочник.Номенклатура
ГДЕ
ВидНоменклатуры = &ВидТовара
)
В данном случае СУБД может выполнить вложенный запрос для каждой строки основной таблицы, что критически замедлит выполнение. Выясним причину: отсутствие типизации и индексов для промежуточного результата.
Для оптимизации подобных сценариев мы рекомендуем использовать механизм временных таблиц, предоставляемый объектом МенеджерВременныхТаблиц. Это позволяет разбить один громоздкий запрос на несколько простых этапов, каждый из которых СУБД может обработать максимально эффективно.
Разберем по шагам правильный алгоритм работы:
МенеджерВременныхТаблиц.Посмотрим на пример реализации этого подхода в коде 1С:
// Создаем менеджер для хранения временных таблиц
МенеджерВТ = Новый МенеджерВременныхТаблиц;
Запрос = Новый Запрос;
Запрос.МенеджерВременныхТаблиц = МенеджерВТ;
// Шаг 1: Подготовка списка фильтрации
Запрос.Текст =
"ВЫБРАТЬ
| Номенклатура КАК Ссылка
|ПОМЕСТИТЬ ВТ_СписокТоваров
|ИЗ
| Справочник.Номенклатура
|ГДЕ
| ВидНоменклатуры = &ВидТовара
|;
|////////////////////////////////////////////////////////////////////////////////
|ВЫБРАТЬ
| Продажи.Номенклатура,
| Продажи.КоличествоОборот
|ИЗ
| РегистрНакопления.Продажи.Обороты(&НачалоПериода, &КонецПериода) КАК Продажи
|ГДЕ
| Продажи.Номенклатура В (ВЫБРАТЬ Ссылка ИЗ ВТ_СписокТоваров)";
Запрос.УстановитьПараметр("ВидТовара", ВидТовара);
Запрос.УстановитьПараметр("НачалоПериода", НачалоПериода);
Запрос.УстановитьПараметр("КонецПериода", КонецПериода);
Результат = Запрос.Выполнить();
Рассмотрим подробнее внутренние механизмы. При использовании временной таблицы с ключевым словом ПОМЕСТИТЬ, платформа 1С создает реальную физическую таблицу в базе данных (в базе tempdb для MS SQL). Это позволяет планировщику СУБД:
Важный момент: если данных во временной таблице много (более 100 строк), индексация становится критически важной. Проанализируем, как добавить индекс к временной таблице прямо в тексте запроса:
ВЫБРАТЬ
Номенклатура КАК Ссылка
ПОМЕСТИТЬ ВТ_ТоварыДляАнализа
ИЗ
Справочник.Номенклатура
ГДЕ
ЭтоГруппа = ЛОЖЬ
ИНДЕКСИРОВАТЬ ПО
Ссылка
;
После добавления инструкции ИНДЕКСИРОВАТЬ ПО последующие соединения с этой таблицей будут проходить практически мгновенно, так как СУБД будет использовать операцию Index Seek вместо Full Scan.
Рассмотрим ситуации, которые могут свести на нет всю пользу от оптимизации:
МенеджерВременныхТаблиц для множества разных задач в рамках одной процедуры, не забывайте очищать ненужные таблицы, чтобы не переполнять системную базу tempdb. Используйте команду УНИЧТОЖИТЬ.Пример уничтожения таблицы:
Запрос.Текст = "УНИЧТОЖИТЬ ВТ_СписокТоваров";
Запрос.Выполнить();
Особое внимание стоит уделить работе с виртуальными таблицами остатков и оборотов. В 1С крайне не рекомендуется выполнять соединения с виртуальными таблицами напрямую. Проанализируем ситуацию: если нам нужно получить остатки по конкретному списку договоров, правильнее сначала поместить список договоров во временную таблицу, а затем передать этот список в параметры виртуальной таблицы.
Разберем пример эффективного получения остатков:
// Сначала подготавливаем фильтр
Запрос.Текст =
"ВЫБРАТЬ Ссылка ПОМЕСТИТЬ ВТ_Фильтр ИЗ Справочник.Договоры ГДЕ Организация = &Организация;
|////////////////////////////////////////////////////////////////////////////////
|ВЫБРАТЬ
| Остатки.Счет,
| Остатки.СуммаОстаток
|ИЗ
| РегистрБухгалтерии.Хозрасчетный.Остатки(&Период, , , Договор В (ВЫБРАТЬ Ссылка ИЗ ВТ_Фильтр)) КАК Остатки";
Обратите внимание: мы передаем условие через В (ВЫБРАТЬ Ссылка ИЗ ВТ_Фильтр) непосредственно в параметры виртуальной таблицы. Это позволяет платформе 1С оптимизировать SQL-запрос еще на этапе обращения к итогам регистра, не вычитывая лишние данные в память сервера приложений.
Мы выяснили, что временные таблицы — это мощный инструмент в руках разработчика 1С для управления производительностью системы. Рассмотрим основные правила, которые помогут вам писать быстрый код:
Соблюдение этих простых принципов позволит вашим отчетам работать стабильно даже на очень больших объемах данных, обеспечивая комфортную работу пользователей системы.