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