Что быстрее и эффективнее в 1С: обход выборки запроса или выгрузка в таблицу значений?

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

В процессе разработки на платформе 1С:Предприятие 8 перед программистом часто встает выбор: как обработать результат выполнения запроса? Существует два основных пути: использовать последовательный обход через Выбрать() или же сразу поместить все данные в оперативную память с помощью Выгрузить() в таблицу значений. На первый взгляд может показаться, что работа с таблицей значений удобнее и быстрее, однако при росте объемов данных этот подход может стать «миной замедленного действия». Для интерактивной отладки запросов и экспериментов с алгоритмами обработки результатов можно задействовать консоль запросов для управляемых форм.

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

Разберем механизм работы метода Выбрать()

Метод Выбрать() создает объект типа ВыборкаИзРезультатаЗапроса. Давайте рассмотрим, как платформа управляет данными в этом случае. Основная особенность выборки — потоковая обработка. Платформа не стремится загрузить абсолютно все данные в оперативную память сервера приложений в один момент.

Если результат запроса невелик, он обрабатывается в ОЗУ. Однако, если объем данных превышает определенный порог (в современных реализациях платформы это обычно около 64 Мб), система задействует механизм временных файлов. Результат записывается на диск в папку временных файлов сеанса, и при вызове метода Следующий() платформа подгружает данные порциями. Это делает работу с выборкой крайне устойчивой к огромным объемам информации. Даже если ваш запрос возвращает миллионы строк, процесс не упадет с ошибкой «Нехватка памяти», хотя скорость обхода будет зависеть от производительности дисковой подсистемы.

Посмотрим на классический пример обхода выборки:


Запрос = Новый Запрос;
Запрос.Текст = 
    "ВЫБРАТЬ
    |   Продажи.Номенклатура КАК Номенклатура,
    |   Продажи.КоличествоОбороты КАК Количество
    |ИЗ
    |   РегистрНакопления.Продажи.Обороты(&Начало, &Конец) КАК Продажи";

РезультатЗапроса = Запрос.Выполнить();
Выборка = РезультатЗапроса.Выбрать();

Пока Выборка.Следующий() Цикл
    // Обрабатываем данные по одной строке
    Сообщить(Выборка.Номенклатура);
КонецЦикла;

Проанализируем работу метода Выгрузить()

Метод Выгрузить() ведет себя иначе. При его вызове платформа создает объект ТаблицаЗначений и копирует в него все данные из внутреннего буфера запроса. Это влечет за собой несколько важных последствий:

  1. Аллокация памяти: Таблице значений требуется непрерывный блок адресного пространства. При больших объемах данных (сотни тысяч или миллионы строк) система может не найти подходящего блока в ОЗУ, что приведет к аварийному завершению работы процесса.
  2. Затраты на создание объекта: Копирование данных из результата запроса в структуру таблицы — это дополнительная операция, которая требует времени и ресурсов процессора.
  3. Сериализация: Если код выполняется на сервере, а таблицу значений нужно передать на клиент, она будет полностью сериализована (преобразована в XML или внутренний формат), что создаст огромную нагрузку на сеть.

Рассмотрим ситуацию, когда выгрузка в ТЗ не оправдана:


РезультатЗапроса = Запрос.Выполнить();
// Неправильно: лишнее потребление памяти при простом обходе
ТЗ = РезультатЗапроса.Выгрузить();
Для Каждого СтрокаТЗ Из ТЗ Цикл
    ОбработатьДанные(СтрокаТЗ.Номенклатура);
КонецЦикла;

Выясним причину: почему бытует мнение, что Выбрать() обращается к СУБД на каждом шаге?

Среди начинающих разработчиков существует миф, что метод Выполнить() только подготавливает запрос, а каждое обращение к Выборка.Следующий() инициирует поход в SQL-сервер. Это не так.

Давайте проясним: взаимодействие с СУБД (например, MS SQL Server или PostgreSQL) происходит в момент вызова метода Выполнить(). Именно тогда запрос исполняется на стороне базы данных, и весь результирующий набор данных передается на сервер приложений 1С. Разница между Выбрать() и Выгрузить() заключается исключительно в том, как эти уже полученные данные будут представлены прикладному коду внутри сервера приложений.

Сравним функциональные возможности

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

Преимущества выборки:

Преимущества таблицы значений:

Посмотрим на официальные стандарты разработки 1С

Фирма 1С в своих методических рекомендациях и требованиях к экзамену «1С:Специалист» четко указывает: выгрузка результата запроса в таблицу значений без явной необходимости считается ошибкой. Для выявления последствий подобных ошибок или некорректных доработок можно автоматически сверять бухгалтерские данные между базами 1С.

Система стандартов гласит, что при потенциально неограниченных выборках (например, справочник «Номенклатура» или регистр «Продажи», которые могут расти годами) следует использовать только последовательный обход. Выгрузка в таблицу значений допустима только если:

  1. Требуется многократный поиск в полученных данных; например, при сопоставлении объектов по произвольным полям в ходе миграции можно использовать обработку для переноса данных между похожими конфигурациями 1С.
  2. Необходимо передать данные в методы, требующие объект ТаблицаЗначений.
  3. Объем данных гарантированно мал и ограничен спецификой задачи (например, выборка из перечисления или небольшой константы).

Итоги: что же выбрать?

Подводя итог, проанализируем типичный алгоритм выбора метода разработчиком:

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

Если же логика задачи требует сложной постобработки данных, которую невозможно реализовать средствами самого SQL-запроса (например, хитрые сортировки или специфические группировки в коде), то выгружайте результат в ТаблицуЗначений, но при этом старайтесь максимально ограничить количество выбираемых данных с помощью условий ГДЕ в запросе.

Помните, что оптимизация использования оперативной памяти — это один из ключевых факторов масштабируемости систем на платформе 1С:Предприятие 8, и в высоконагруженных конфигурациях для этих целей может применяться многопоточная свёртка 1С:ERP.

← На главную