Работа с запросами в 1С:Предприятие 8.3 — одна из самых востребованных задач для разработчиков. Часто результат запроса нужно не просто получить, а перебрать построчно, обработать данные или преобразовать их для дальнейшего использования. Однако не все знают, что существует несколько способов перебора — от элементарного цикла Для Каждого до оптимизированных методов с использованием Выгрузить() или Поместить().
В этой статье разберём 5 практических подходов к перебору запросов в 1С, их плюсы и минусы, а также типичные ошибки, которые допускают даже опытные программисты. Особое внимание уделим производительности — ведь неправильный перебор может замедлить работу системы в десятки раз, особенно при больших объёмах данных.
1. Классический перебор через «Для Каждого»
Самый простой и интуитивно понятный способ — использование конструкции Для Каждого ... Из ... Цикл. Он подходит для большинства задач, где нужно последовательно обработать каждую строку результата запроса.
Пример кода:
Запрос = Новый Запрос;
Запрос.Текст =
"ВЫБРАТЬ
| Номенклатура.Наименование,
| Номенклатура.Артикул
|ИЗ
| Справочник.Номенклатура КАК Номенклатура";
РезультатЗапроса = Запрос.Выполнить();
Выборка = РезультатЗапроса.Выбрать();
Пока Выборка.Следующий() Цикл
Сообщить(Выборка.Наименование + " (" + Выборка.Артикул + ")");
КонецЦикла;
Этот метод удобен своей наглядностью, но имеет два существенных недостатка:
- 🐢 Низкая производительность при больших выборках (тысячи строк) из-за построчного чтения.
- 🔄 Невозможность параллельной обработки — данные читаются последовательно.
Если вам нужно только количество строк в результате запроса, используйте РезультатЗапроса.Выбрать().Количество() вместо полного перебора — это сэкономит ресурсы.
2. Перебор с выгрузкой в таблицу значений
Более эффективный способ — выгрузить результат запроса в таблицу значений и уже её перебирать. Это особенно актуально, если данные нужно не только читать, но и модифицировать.
Пример:
РезультатЗапроса = Запрос.Выполнить();
ТаблицаДанных = РезультатЗапроса.Выгрузить();
Для Каждого Строка Из ТаблицаДанных Цикл
Если НЕ ЗначениеЗаполнено(Строка.Артикул) Тогда
Строка.Артикул = "БЕЗ_АРТИКУЛА";
КонецЕсли;
КонецЦикла;
Преимущества метода:
- ⚡ Быстрее, чем построчный перебор, так как данные загружаются в память сразу.
- 🔧 Удобно для модификации — можно изменять значения прямо в таблице.
- 📊 Поддерживает сортировку и фильтрацию уже после выгрузки.
Когда НЕ стоит использовать выгрузку в таблицу значений?
Если запрос возвращает миллионы строк, выгрузка может привести к переполнению памяти. В таких случаях лучше использовать Поместить() или потоковую обработку.
3. Использование метода «Поместить()» для массовой обработки
Метод Поместить() позволяет разместить результат запроса в коллекции (массиве, структуре, соответствии) и затем работать с ней. Это полезно, когда нужно сгруппировать данные или быстро получить доступ к конкретным строкам.
Пример с помещением в массив:
РезультатЗапроса = Запрос.Выполнить();
МассивДанных = Новый Массив;
РезультатЗапроса.Выбрать();
Пока РезультатЗапроса.Следующий() Цикл
МассивДанных.Добавить(РезультатЗапроса.Поместить(Новый Структура("Наименование, Артикул")));
КонецЦикла;
Где это применимо:
- 📦 Группировка данных по ключевому полю (например, по контрагенту).
- 🔍 Быстрый поиск по индексу (если использовать
Соответствие). - 🔄 Кэширование часто используемых данных.
4. Пакетная обработка с использованием «ВыбратьПачками()»
Для обработки очень больших выборок (десятки тысяч строк) в 1С 8.3 появился метод ВыбратьПачками(). Он позволяет читать данные порциями, не перегружая память.
Пример:
Выборка = РезультатЗапроса.ВыбратьПачками(1000); // Пачка по 1000 строк
Пока Выборка.СледующаяПачка() Цикл
Пока Выборка.Следующий() Цикл
// Обработка строки
КонецЦикла;
КонецЦикла;
Когда это актуально:
| Ситуация | Рекомендуемый размер пачки | Примечание |
|---|---|---|
| Обновление справочников | 500–2000 строк | Зависит от объёма транзакций |
| Экспорт данных в файл | 1000–5000 строк | Уменьшает нагрузку на диск |
| Аналитика по большим периодам | 200–1000 строк | Часто требует дополнительной агрегации |
Метод ВыбратьПачками() — единственный безопасный способ обработать запрос с миллионами строк без риска переполнения памяти.
5. Оптимизация перебора с помощью временных таблиц
Если запрос выполняется многократно или данные нужны в нескольких местах кода, имеет смысл сохранить результат во временной таблице. Это ускорит последующие обращения.
Пример:
Запрос = Новый Запрос;
Запрос.Текст =
"ВЫБРАТЬ
| Товары.Ссылка КАК Ссылка,
| Товары.Цена КАК Цена
|ПОМЕСТИТЬ ВТ_Товары
|ИЗ
| Справочник.Товары КАК Товары";
Запрос.Выполнить();
// Далее работаем с ВТ_Товары
ВременнаяТаблица = Запрос.Выполнить().ПолучитьВременнуюТаблицу("ВТ_Товары");
Преимущества временных таблиц:
- ⚡ Ускорение повторных запросов — данные уже подготовлены.
- 🔧 Упрощение сложных отчётов — можно разбить логику на этапы.
- 📈 Снижение нагрузки на СУБД, так как запрос выполняется один раз.
Запрос выполняется больше 1 раза|Нужно объединить данные из нескольких источников|Требуется промежуточная обработка|Работа с большими объёмами данных-->
Типичные ошибки и как их избежать
Даже опытные разработчики иногда допускают ошибки при переборе запросов. Вот самые распространённые:
⚠️ Внимание: Если в запросе используются функцииВЫБРАТЬ РАЗЛИЧНЫЕилиГРУППИРОВКА, убедитесь, что перебор учитывает уникальность строк. Иначе можно пропустить данные или получить дубли.
Ошибка 1: Забывают закрыть выборку
Если не вызвать Выборка.Закрыть() после обработки, это может привести к утечкам памяти. Хотя в новых версиях 1С это делается автоматически, явно закрывать выборку считается хорошим тоном.
Ошибка 2: Перебор без проверки на пустоту
Всегда проверяйте, что запрос вернул данные:
Если НЕ РезультатЗапроса.Пустой() Тогда
// Перебор
КонецЕсли;
Ошибка 3: Избыточная выгрузка в память
Не выгружайте в таблицу значений миллионы строк — это приведёт к Недостаточно памяти. Используйте ВыбратьПачками() или потоковую обработку.
Сравнение методов перебора: что выбрать?
Какой способ оптимален для вашей задачи? Вот краткое сравнение:
| Метод | Скорость | Память | Когда использовать |
|---|---|---|---|
Для Каждого |
Низкая | Минимальная | Малые выборки, простые задачи |
Выгрузить() |
Средняя | Высокая | Средние выборки, модификация данных |
Поместить() |
Высокая | Средняя | Группировка, поиск по ключу |
ВыбратьПачками() |
Низкая (но стабильная) | Минимальная | Очень большие выборки |
| Временные таблицы | Очень высокая | Средняя | Многократное использование данных |
Для 90% задач оптимален вариант с Выгрузить() в таблицу значений. Он балансирует между скоростью и удобством.
FAQ: Частые вопросы по перебору запросов в 1С
Можно ли перебирать запрос в обратном порядке?
Да, но не напрямую. После выгрузки в таблицу значений можно отсортировать её по убыванию и затем перебирать:
Таблица.Сортировать("Дата Убыв");
Для Каждого Строка Из Таблица Цикл
// Перебор с конца
КонецЦикла;
Как перебрать запрос с вложенными таблицами (иерархия)?
Используйте конструкцию ВЫБРАТЬ ... ПОМЕСТИТЬ ВТ_ВложеннаяТаблица, а затем обрабатывайте основную и вложенную таблицы отдельно. Пример:
Запрос.Текст =
"ВЫБРАТЬ
| Заказы.Номер КАК Номер,
| Заказы.Дата КАК Дата
|ПОМЕСТИТЬ ВТ_Заказы
|ИЗ
| Документ.ЗаказКлиента КАК Заказы
|
|////////////////////////////////////////////////
|ВЫБРАТЬ
| ВТ_Заказы.Номер КАК НомерЗаказа,
| ЗаказыСтроки.Номенклатура КАК Номенклатура
|ПОМЕСТИТЬ ВТ_СтрокиЗаказов
|ИЗ
| ВТ_Заказы КАК ВТ_Заказы
| ЛЕВОЕ СОЕДИНЕНИЕ Документ.ЗаказКлиента.Строки КАК ЗаказыСтроки
| ПО ВТ_Заказы.Номер = ЗаказыСтроки.Ссылка.Номер";
Почему при переборе выдаётся ошибка «Объект не найден»?
Это происходит, если в запросе есть ссылки на удалённые объекты (например, справочники или документы). Перед перебором проверяйте существование объектов:
Если НЕ Выборка.Ссылка.Пустая() И НЕ Выборка.Ссылка.ПометкаУдаления Тогда
// Обработка
КонецЕсли;
Как ускорить перебор запроса с joins (соединениями)?
Соединения (ЛЕВОЕ СОЕДИНЕНИЕ, ВНУТРЕННЕЕ СОЕДИНЕНИЕ) замедляют запрос. Оптимизируйте их:
- 🔹 Используйте индексированные поля для соединений.
- 🔹 Разбивайте сложные запросы на несколько простых с временными таблицами.
- 🔹 Избегайте
ВЫБРАТЬ *— указывайте только нужные поля.
Можно ли параллельно перебирать несколько запросов?
В 1С 8.3 нет встроенной многопоточности, но можно эмулировать параллельность с помощью ФоновыеЗадачи (начиная с версии 8.3.10). Пример:
ФоновыеЗадачи.ДобавитьВОчередь("ОбработатьДанные", РезультатЗапроса1);
ФоновыеЗадачи.ДобавитьВОчередь("ОбработатьДанные", РезультатЗапроса2);
Однако учитывайте, что это увеличивает нагрузку на сервер.