Вопрос оптимизации работы с базой данных — один из ключевых для разработчика 1С. Часто возникает дилемма: написать один большой пакетный запрос или разбить логику на несколько последовательных вызовов метода Выполнить(). На первый взгляд может показаться, что разницы нет, или она сводится лишь к стилю написания кода. Однако, если мы углубимся в механику работы платформы и СУБД, мы увидим существенные отличия.
Давайте подробно разберем, какие преимущества дает использование метода ВыполнитьПакет() и почему в большинстве типовых конфигураций (например, в УТ 11 или ERP) используется именно этот подход.
Главный аргумент в пользу пакетного запроса — это производительность, связанная с сетевыми задержками и количеством обращений (round-trips).
Разберем процесс выполнения запроса:
Запрос.Выполнить() инициирует отдельное обращение к серверу приложений 1С. Если у вас 5 запросов, это 5 "путешествий" данных по сети. Метод Запрос.ВыполнитьПакет() делает это за один раз.;, и отправляет его СУБД.Почему это важно? Каждый отдельный запрос заставляет SQL-сервер тратить ресурсы на парсинг (разбор) текста запроса и построение плана выполнения. Пакетная отправка снижает нагрузку на сетевой канал между серверами и позволяет СУБД обработать инструкции блоком.
Это, пожалуй, самое удобное преимущество для программиста. При последовательном выполнении запросов, чтобы передать данные из первого запроса во второй через временную таблицу, нам необходимо явно создавать объект МенеджерВременныхТаблиц.
В случае с последовательными запросами код выглядит так:
МенеджерВТ = Новый МенеджерВременныхТаблиц;
Запрос = Новый Запрос;
Запрос.МенеджерВременныхТаблиц = МенеджерВТ;
// Первый запрос - помещаем данные
Запрос.Текст = "ВЫБРАТЬ ... ПОМЕСТИТЬ ВТ ...";
Запрос.Выполнить();
// Второй запрос - используем данные
Запрос.Текст = "ВЫБРАТЬ ... ИЗ ВТ ...";
Результат = Запрос.Выполнить();
При использовании пакетного запроса, все запросы внутри пакета разделяют единый контекст. Нам не нужно заботиться о создании менеджера временных таблиц вручную. Временные таблицы, созданные в первой части пакета, автоматически видны в последующих частях и уничтожаются после завершения выполнения пакета.
Запрос.Текст = "
|ВЫБРАТЬ ... ПОМЕСТИТЬ ВТ ИЗ ...
|;
|ВЫБРАТЬ ... ИЗ ВТ ...";
Результаты = Запрос.ВыполнитьПакет();
В обсуждении часто упоминается неудобство пакетных запросов: результат метода ВыполнитьПакет() — это массив. Если мы вставляем новый запрос в середину пакета, индексы массива сдвигаются (было Результаты[1], стало Результаты[2]), и приходится переписывать код обработки результатов.
Однако этот недостаток легко обходится правильным проектированием текста запроса. Давайте применим инструкцию УНИЧТОЖИТЬ.
Правило: Если часть пакета формирует временную таблицу и она больше не нужна для выборки данных в 1С, ее следует уничтожить в конце пакета или явно не выбирать данные из нее без помещения.
Запросы, которые выполняют только помещение во временную таблицу (ПОМЕСТИТЬ) или уничтожение (УНИЧТОЖИТЬ), не возвращают результат в итоговый массив пакета (или возвращают пустой элемент, который можно игнорировать, если грамотно структурировать финальную выборку).
Лучшая практика — делать так, чтобы пакет возвращал результаты только в тех частях, которые реально нужны во встроенном языке.
Если у вас есть сложный алгоритм, состоящий из 5 последовательных запросов, использующих один менеджер временных таблиц, отладить его в Консоли запросов бывает непросто. Вам придется копировать тексты по частям или эмулировать выполнение.
Пакетный запрос можно просто скопировать целиком в Консоль запросов. Консоль прекрасно понимает разделитель ;, выполнит весь пакет, покажет содержимое всех временных таблиц и результаты всех выборок. Это значительно ускоряет поиск ошибок.
Хотя сам по себе ВыполнитьПакет() не открывает явную транзакцию (если вы не сделали это через НачатьТранзакцию), он обеспечивает лучшую согласованность данных (Read Consistency) в рамках одного вызова. Оптимизатор СУБД видит весь батч целиком и может построить более оптимальный план выполнения, понимая, как используются данные.
Давайте подведем итог. Мы рекомендуем использовать пакетные запросы (ВыполнитьПакет) практически всегда, когда логика требует нескольких связанных выборок данных.
Преимущества:
Когда использовать отдельные запросы? Лишь в редких случаях, когда логика выполнения второго запроса зависит от анализа данных, полученных в первом, на стороне приложения 1С (например: "Если в первом запросе сумма > 100, то выполняем второй запрос по одной логике, иначе — формируем совершенно другой текст запроса"). Но даже в этом случае часто можно использовать ВЫБОР КОГДА внутри самого запроса.