Многие начинающие (и не только) разработчики сталкиваются с дилеммой: удобно ли выполнять Запрос внутри цикла, если мы всего лишь соединяем данные из таблиц значений? На первый взгляд кажется, что если мы не обращаемся к метаданным конфигурации, то это «безопасно» и «быстро». Однако, давайте разберемся, почему этот подход считается грубой ошибкой в архитектуре 1С и как сделать правильно.
Основная проблема заключается в накладных расходах на выполнение каждого запроса. Даже если запрос максимально прост, для платформы 1С каждый вызов объекта Запрос — это самостоятельное событие.
Профессиональный подход заключается в минимизации обращений к серверу СУБД. Рассмотрим несколько стратегий, которые позволят вам отказаться от опасных конструкций.
Один из самых эффективных способов — использование СКД с набором данных типа «Объект». Это позволяет передать ваши таблицы значений непосредственно в процессор компоновки данных. Соединение данных происходит полностью в оперативной памяти сервера 1С, без создания временных таблиц в базе данных.
Для реализации этого метода вы можете использовать следующий подход:
// Пример подготовки набора данных
СхемаКомпоновки = Новый СхемаКомпоновкиДанных;
Источник = СхемаКомпоновки.ИсточникиДанных.Добавить();
Источник.ТипИсточникаДанных = \"Local\";
НаборДанных = СхемаКомпоновки.НаборыДанных.Добавить(Тип(\"НаборДанныхОбъектСхемыКомпоновкиДанных\"));
НаборДанных.ИмяОбъектаДанных = \"МояТаблица\";
// Далее настраиваем процессор компоновки и передаем ТЗ через внешние наборы данных
Настройки = СхемаКомпоновки.НастройкиПоУмолчанию;
ВнешниеНаборы = Новый Структура(\"МояТаблица\", ТаблицаЗначений);
ПроцессорКомпоновки = Новый ПроцессорКомпоновкиДанных;
ПроцессорКомпоновки.Инициализировать(Макет, ВнешниеНаборы);
Если задача заключается в простом соединении двух коллекций, часто использование метода НайтиСтроки() или обход вложенными циклами (с предварительной индексацией одной из таблиц) будет на порядки быстрее, чем любой запрос.
Рассмотрим пример правильной подготовки данных для быстрого поиска:
// Индексируем таблицу, по которой будем искать
ТаблицаДляПоиска.Индексы.Добавить(\"КодТовара\");
Для Каждого Строка Из ОсновнаяТаблица Цикл
СтруктураПоиска = Новый Структура(\"КодТовара\", Строка.КодТовара);
НайденныеСтроки = ТаблицаДляПоиска.НайтиСтроки(СтруктураПоиска);
// Обработка данных...
КонецЦикла;
Если вам все же необходима мощь языка запросов (например, для сложных левых соединений или группировок), лучше всего собрать все необходимые данные в одну общую структуру или массив структур перед выполнением запроса.
Вместо множества запросов подготовьте временную таблицу один раз:
Запрос = Новый Запрос;
Запрос.Текст =
\"ВЫБРАТЬ * ПОМЕСТИТЬ ВТ_Данные ИЗ &Таблица КАК Т
;
ВЫБРАТЬ * ИЗ ВТ_Данные КАК Т1 ЛЕВОЕ СОЕДИНЕНИЕ ЕщеТаблица КАК Т2 ПО Т1.Ключ = Т2.Ключ\";
Запрос.УстановитьПараметр(\"Таблица\", ОбщаяТаблицаЗначений);
Результат = Запрос.Выполнить();
Главный совет: всегда стремитесь к выполнению одного запроса вместо цикла. Профессионалы ценятся не за умение писать сложный код, а за умение правильно оценивать план выполнения запроса и объем передаваемых данных. Если вы чувствуете необходимость «завернуть» запрос в цикл — остановитесь и подумайте, как можно перестроить логику, чтобы объединить данные до передачи их в механизм запросов. Это сэкономит ресурсы сервера и обеспечит стабильную работу вашей программы при любых объемах данных.