При разработке на платформе 1С:Предприятие 8.3 программисты часто сталкиваются с дилеммой: передать список ссылок (например, массив контрагентов) напрямую в параметр запроса или предварительно поместить эти данные во временную таблицу. Особенно остро этот вопрос встает, когда количество элементов в списке исчисляется тысячами. Разберем детально, как работает платформа «под капотом», и выясним, какую стратегию выбрать для оптимальной производительности.
Рассмотрим стандартную ситуацию: нам нужно выбрать данные из справочника, отфильтровав их по массиву СписокКонтрагентов. В коде это выглядит так:
Запрос = Новый Запрос;
Запрос.Текст =
"ВЫБРАТЬ
| Контрагенты.Ссылка КАК Ссылка,
| Контрагенты.ИНН КАК ИНН
|ИЗ
| Справочник.Контрагенты КАК Контрагенты
|ГДЕ
| Контрагенты.Ссылка В (&СписокКонтрагентов)";
Запрос.УстановитьПараметр("СписокКонтрагентов", МассивСсылок);
Результат = Запрос.Выполнить();
Многие разработчики опасаются, что при большом количестве элементов в МассивСсылок (например, 10 000 записей), СУБД получит гигантский запрос с перечислением всех идентификаторов через запятую. Однако проанализируем поведение платформы 1С. Начиная с определенных версий, 1С применяет встроенную оптимизацию:
IN (guid1, guid2, ...).В (&Параметр) на внутреннее соединение с этой таблицей.Таким образом, даже если мы передадим огромный массив, платформа постарается не «уронить» SQL-сервер слишком длинным текстом запроса. Но значит ли это, что об оптимизации можно забыть? Выясним это далее.
Несмотря на автоматику, использование МенеджерВременныхТаблиц часто оказывается более эффективным и «чистым» решением. Рассмотрим ситуацию, когда данные для фильтрации уже получены в ходе выполнения программы другим запросом. Проанализируем типичную ошибку legacy-кода: выгрузка результата первого запроса в массив и передача его во второй запрос.
Рассмотрим пример «плохого» кода:
// Первый запрос получает список нужных ссылок
Результат1 = Запрос1.Выполнить().Выгрузить();
МассивСсылок = Результат1.ВыгрузитьКолонку("Ссылка");
// Второй запрос использует этот массив
Запрос2.Текст = "ВЫБРАТЬ ... ГДЕ Ссылка В (&МассивСсылок)";
Запрос2.УстановитьПараметр("МассивСсылок", МассивСсылок);
В этой схеме данные совершают лишний круг: СУБД -> Сервер 1С (память rphost) -> СУБД. Это нерационально расходует оперативную память сервера приложений и создает лишнюю сетевую нагрузку. Гораздо правильнее использовать один пакетный запрос с помещением данных во временную таблицу.
Посмотрим на оптимизированный вариант:
МенеджерВТ = Новый МенеджерВременныхТаблиц;
Запрос = Новый Запрос;
Запрос.МенеджерВременныхТаблиц = МенеджерВТ;
Запрос.Текст =
"ВЫБРАТЬ
| НужныеСсылки.Ссылка КАК Ссылка
|ПОМЕСТИТЬ ВТ_Отбор
|ИЗ
| &ТЗ_Данных КАК НужныеСсылки
|;
|
|ВЫБРАТЬ
| Контрагенты.Ссылка,
| Контрагенты.Наименование
|ИЗ
| Справочник.Контрагенты КАК Контрагенты
|ИННЕР СОЕДИНЕНИЕ ВТ_Отбор КАК ВТ_Отбор
| ПО Контрагенты.Ссылка = ВТ_Отбор.Ссылка";
Запрос.УстановитьПараметр("ТЗ_Данных", ТаблицаСДанными);
Запрос.Выполнить();
При работе с очень большими объемами данных во временных таблицах (десятки и сотни тысяч строк) критически важно помнить про индексацию. Если мы просто поместим данные в ВТ, СУБД может выбрать неоптимальный план соединения (например, Nested Loops вместо Hash Match), так как у временной таблицы нет статистики.
Чтобы помочь планировщику запросов:
ИНДЕКСИРОВАТЬ ПО в тексте запроса при создании ПОМЕСТИТЬ.Выполнить(), а использовать в другом. Это заставит СУБД обновить статистику по временной таблице.Проанализируем пример с индексацией:
Запрос.Текст =
"ВЫБРАТЬ
| Ссылка
|ПОМЕСТИТЬ ВТ_Список
|ИЗ
| &Массив
|ИНДЕКСИРОВАТЬ ПО
| Ссылка";
Разберем, как разные системы ведут себя при передаче больших списков параметров:
МенеджерВременныхТаблиц полностью снимает этот риск. Современные версии 1С также умеют использовать Table-Valued Parameters (TVP) для быстрой передачи таблиц.IN, но при достижении критических размеров запроса производительность резко падает. Для Postgres временная таблица с последующим JOIN почти всегда быстрее, чем гигантское условие ANY(ARRAY[...]).Проанализировав ситуацию, мы можем сформулировать следующие правила для качественного кода:
ГДЕ ... В (&Список). Это просто и наглядно.; в тексте запроса) и временные таблицы.ТаблицыЗначений в запрос в качестве параметра, всегда сразу делайте ПОМЕСТИТЬ ВТ_Название с индексацией по полям связи.Соблюдение этих принципов позволит вашим приложениям на базе 1С работать быстро даже на очень крупных базах данных, минимизируя нагрузку на сервер и исключая ошибки переполнения параметров СУБД.