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