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