Как лучше выполнять запросы в 1С 8.3: использовать пакетные запросы или несколько отдельных?

Программист 1С v8.3 (Управляемые формы) IT и автоматизация бизнеса
← К списку

При разработке отчетов, обработок или при проведении документов в 1С 8.3, мы часто сталкиваемся с необходимостью получить данные из базы данных. Перед нами встает выбор: составить один сложный пакетный запрос или выполнить несколько отдельных запросов последовательно. Давайте вместе разберем эту ситуацию, проанализируем аргументы "за" и "против" каждого подхода и выясним, когда какой вариант предпочтительнее.

На первый взгляд, может показаться, что между пакетными запросами и несколькими отдельными запросами нет существенной разницы. Однако, как мы с вами увидим, существуют важные нюансы, которые влияют на производительность, читаемость кода, удобство отладки и даже транзакционную целостность данных.

Преимущества и особенности пакетных запросов

Пакетный запрос — это группа запросов, объединенных в один текстовый блок, который выполняется как единое целое. Рассмотрим подробнее его ключевые особенности и преимущества.

  1. Использование временных таблиц (ВТ)

    Одно из самых мощных преимуществ пакетных запросов — это возможность создания и использования временных таблиц. Результаты одного запроса в пакете могут быть помещены во временную таблицу с помощью оператора ПОМЕСТИТЬ, а затем эта таблица может быть использована как источник данных для последующих запросов в том же пакете. Это позволяет нам:

    • Разбивать сложные запросы на логические шаги: Вместо одного огромного и трудночитаемого запроса, мы создаем последовательность более простых запросов, каждый из которых решает свою подзадачу.
    • Улучшать читаемость и поддерживаемость кода: Код становится более модульным и понятным.
    • Избегать повторных расчетов: Если нам нужно несколько раз использовать одни и те же промежуточные данные, мы можем рассчитать их один раз, поместить во временную таблицу и затем многократно к ней обращаться.

    Временные таблицы существуют в течение всего выполнения пакета запросов или до момента их явного уничтожения. Давайте посмотрим на пример:

    
    // Запрос 1: Получаем список товаров из документа и помещаем во временную таблицу
    ВЫБРАТЬ
        Товары.Номенклатура КАК Номенклатура,
        Товары.Количество КАК Количество,
        Товары.Сумма КАК Сумма
    ПОМЕСТИТЬ ВТ_ТоварыДокумента
    ИЗ
        Документ.РеализацияТоваровУслуг.Товары КАК Товары
    ГДЕ
        Товары.Ссылка = &СсылкаДокумента;
    
    // Запрос 2: Используем временную таблицу для получения дополнительных данных по номенклатуре
    ВЫБРАТЬ
        ВТ_ТоварыДокумента.Номенклатура,
        ВТ_ТоварыДокумента.Количество,
        ВТ_ТоварыДокумента.Сумма,
        Номенклатура.ЕдиницаИзмерения,
        Номенклатура.ВидНоменклатуры
    ИЗ
        ВТ_ТоварыДокумента КАК ВТ_ТоварыДокумента
            ЛЕВОЕ СОЕДИНЕНИЕ Справочник.Номенклатура КАК Номенклатура
            ПО ВТ_ТоварыДокумента.Номенклатура = Номенклатура.Ссылка;
    
  2. Производительность

    Пакетные запросы часто показывают лучшую производительность по сравнению с выполнением множества отдельных запросов. Почему это происходит? Мы сокращаем количество обращений к серверу базы данных (так называемые "network round trips"). Хотя каждый запрос в пакете выполняется СУБД как отдельный запрос, весь пакет обрабатывается в рамках одного сеанса соединения. Это снижает накладные расходы на установление связи и передачу данных. Оптимизатор запросов СУБД также может эффективнее построить план выполнения для всего пакета, учитывая взаимосвязи между его частями, особенно при использовании временных таблиц.

    Как мы видим из обсуждений, некоторые коллеги отмечают, что "планировщик загружается один раз", и это действительно может дать прирост производительности, особенно при большом количестве операций.

  3. Транзакционная целостность

    Пакетные запросы обычно выполняются в рамках одной транзакции. Это обеспечивает целостность данных. Если один из запросов в пакете завершится ошибкой, все изменения, сделанные предыдущими запросами в этом пакете, могут быть отменены (откачены). Это очень важно для надежности системы.

  4. Удобство отладки и разработки

    Платформа 1С и ее Конструктор запросов полностью поддерживают создание и редактирование пакетных запросов. Это значительно упрощает отладку, так как весь текст запроса, включая создание временных таблиц и их использование, находится в одном месте и может быть выполнен целиком в консоли запросов. Если же мы используем отдельные запросы, особенно те, которые зависят от результатов предыдущих запросов (например, через МенеджерВременныхТаблиц), отладка может быть более трудоемкой, требуя пошагового выполнения и копирования частей запросов по отдельности.

  5. Снижение блокировок

    Использование временных таблиц в пакетных запросах может помочь уменьшить количество блокировок на основных таблицах базы данных. Мы копируем необходимые данные во временную таблицу, а затем работаем с этой копией, что потенциально улучшает параллелизм и общую производительность системы, так как основные таблицы освобождаются быстрее.

Особенности обработки платформой 1С

Важно понимать, что платформа 1С действительно выполняет каждый запрос из пакета последовательно на СУБД как отдельный запрос. Однако это происходит в едином контексте, что позволяет передавать временные таблицы между запросами внутри пакета. Для получения результатов пакетного запроса мы можем использовать следующие методы объекта Запрос:

Некоторые коллеги отмечают, что "платформа сейчас дробит пакетный запрос на отдельные". Даже если это так, концептуальные преимущества использования временных таблиц и логического структурирования запросов внутри одного пакета остаются в силе. Мы, как разработчики, все равно получаем выгоду от более чистого кода и использования ВТ.

Использование нескольких отдельных запросов

Теперь давайте рассмотрим альтернативный подход — выполнение нескольких независимых запросов.

При этом подходе мы создаем отдельные объекты Запрос и выполняем их последовательно. Если нам нужны промежуточные результаты, мы можем сохранять их в таблицах значений или использовать объект МенеджерВременныхТаблиц для передачи временных таблиц между разными объектами Запрос.

Преимущества (по мнению некоторых разработчиков)

  1. Простота для независимых операций: Если запросы совершенно не зависят друг от друга и не требуют общих промежуточных данных, их выполнение по отдельности может быть более интуитивным.

  2. Легкость модификации: Как отмечают некоторые коллеги, "при необходимости вставить или убрать входящий запрос нет геморроя с изменением индексов всех остальных". Это может быть актуально для очень простых сценариев, где нет сложных зависимостей через временные таблицы.

Недостатки

  1. Потенциальное снижение производительности: Каждый отдельный запрос требует нового обращения к серверу базы данных, что увеличивает накладные расходы на установление соединения и передачу данных. Это может быть заметно при большом количестве запросов или при выполнении их в цикле.

  2. Усложнение передачи промежуточных данных: Если запросы зависят друг от друга, нам придется использовать МенеджерВременныхТаблиц. Хотя это и позволяет передавать ВТ, это делает код более громоздким и менее удобным для отладки в консоли запросов, так как для проверки всего сценария потребуется несколько отдельных шагов.

    
    // Запрос 1
    Запрос1 = Новый Запрос;
    Запрос1.МенеджерВременныхТаблиц = Новый МенеджерВременныхТаблиц;
    Запрос1.Текст = "
        ВЫБРАТЬ
            Товары.Номенклатура КАК Номенклатура
        ПОМЕСТИТЬ ВТ_ПромежуточныеДанные
        ИЗ
            Документ.РеализацияТоваровУслуг.Товары КАК Товары
        ГДЕ
            Товары.Ссылка = &СсылкаДокумента;
    ";
    Запрос1.УстановитьПараметр("СсылкаДокумента", ДокументСсылка);
    Запрос1.Выполнить(); // Выполняем первый запрос, создаем ВТ
    
    // Запрос 2
    Запрос2 = Новый Запрос;
    Запрос2.МенеджерВременныхТаблиц = Запрос1.МенеджерВременныхТаблиц; // Передаем менеджер ВТ
    Запрос2.Текст = "
        ВЫБРАТЬ
            ВТ_ПромежуточныеДанные.Номенклатура
        ИЗ
            ВТ_ПромежуточныеДанные КАК ВТ_ПромежуточныеДанные;
    ";
    Результат = Запрос2.Выполнить(); // Выполняем второй запрос
    

    Как мы видим, такой код выглядит более объемным и менее "единым", чем пакетный запрос.

  3. Менее очевидная транзакционная целостность: При выполнении отдельных запросов в разных объектах Запрос нам нужно явно управлять транзакциями, если мы хотим обеспечить их атомарность.

Когда что использовать: рекомендации

После детального анализа, мы можем сформулировать следующие рекомендации:

  1. Предпочитайте пакетные запросы в большинстве случаев:

    • Если вам нужно использовать временные таблицы для разбиения сложной логики.
    • Если важна производительность и минимизация обращений к СУБД.
    • Если запросы логически связаны и их результаты зависят друг от друга.
    • Если вы формируете сложные отчеты или запросы при проведении документов (как, например, в типовых конфигурациях, таких как УТ11).
    • Для улучшения читаемости и поддерживаемости кода.
    • Для более удобной отладки всего запроса целиком в консоли.
  2. Используйте несколько отдельных запросов только в простых и независимых случаях:

    • Если запросы абсолютно независимы друг от друга, не используют общие промежуточные данные и не требуют сложной логики.
    • Если вы выполняете очень простые, единичные выборки данных, где накладные расходы на пакетный запрос не оправданы (хотя это редкость и разница будет минимальной).
    • Для быстрого "ad-hoc" получения данных, когда нет необходимости в сложной структуре.

Таким образом, утверждение о том, что "никаких отличий" нет, не совсем корректно. Хотя для очень простых, независимых запросов разница может быть неощутимой, при наличии сложных сценариев, требующих промежуточных вычислений или доступа к одним и тем же данным несколько раз, пакетные запросы с временными таблицами предоставляют значительные преимущества в производительности, структурированности и надежности по сравнению с последовательным выполнением отдельных запросов.

В итоге, мы с вами выяснили, что пакетные запросы являются более мощным и предпочтительным инструментом для большинства задач в 1С 8.3, особенно когда речь идет о комплексных выборках данных и оптимизации работы с базой.

← К списку