В процессе разработки на платформе 1С:Предприятие 8 перед программистом часто встает выбор: как обработать результат выполнения запроса? Существует два основных пути: использовать последовательный обход через Выбрать() или же сразу поместить все данные в оперативную память с помощью Выгрузить() в таблицу значений. На первый взгляд может показаться, что работа с таблицей значений удобнее и быстрее, однако при росте объемов данных этот подход может стать «миной замедленного действия». Для интерактивной отладки запросов и экспериментов с алгоритмами обработки результатов можно задействовать консоль запросов для управляемых форм.
В этой статье мы подробно разберем внутренние механизмы платформы, проанализируем влияние каждого метода на память и производительность, а также выясним, почему официальные стандарты разработки 1С отдают предпочтение именно выборке.
Метод Выбрать() создает объект типа ВыборкаИзРезультатаЗапроса. Давайте рассмотрим, как платформа управляет данными в этом случае. Основная особенность выборки — потоковая обработка. Платформа не стремится загрузить абсолютно все данные в оперативную память сервера приложений в один момент.
Если результат запроса невелик, он обрабатывается в ОЗУ. Однако, если объем данных превышает определенный порог (в современных реализациях платформы это обычно около 64 Мб), система задействует механизм временных файлов. Результат записывается на диск в папку временных файлов сеанса, и при вызове метода Следующий() платформа подгружает данные порциями. Это делает работу с выборкой крайне устойчивой к огромным объемам информации. Даже если ваш запрос возвращает миллионы строк, процесс не упадет с ошибкой «Нехватка памяти», хотя скорость обхода будет зависеть от производительности дисковой подсистемы.
Посмотрим на классический пример обхода выборки:
Запрос = Новый Запрос;
Запрос.Текст =
"ВЫБРАТЬ
| Продажи.Номенклатура КАК Номенклатура,
| Продажи.КоличествоОбороты КАК Количество
|ИЗ
| РегистрНакопления.Продажи.Обороты(&Начало, &Конец) КАК Продажи";
РезультатЗапроса = Запрос.Выполнить();
Выборка = РезультатЗапроса.Выбрать();
Пока Выборка.Следующий() Цикл
// Обрабатываем данные по одной строке
Сообщить(Выборка.Номенклатура);
КонецЦикла;
Метод Выгрузить() ведет себя иначе. При его вызове платформа создает объект ТаблицаЗначений и копирует в него все данные из внутреннего буфера запроса. Это влечет за собой несколько важных последствий:
Рассмотрим ситуацию, когда выгрузка в ТЗ не оправдана:
РезультатЗапроса = Запрос.Выполнить();
// Неправильно: лишнее потребление памяти при простом обходе
ТЗ = РезультатЗапроса.Выгрузить();
Для Каждого СтрокаТЗ Из ТЗ Цикл
ОбработатьДанные(СтрокаТЗ.Номенклатура);
КонецЦикла;
Среди начинающих разработчиков существует миф, что метод Выполнить() только подготавливает запрос, а каждое обращение к Выборка.Следующий() инициирует поход в SQL-сервер. Это не так.
Давайте проясним: взаимодействие с СУБД (например, MS SQL Server или PostgreSQL) происходит в момент вызова метода Выполнить(). Именно тогда запрос исполняется на стороне базы данных, и весь результирующий набор данных передается на сервер приложений 1С. Разница между Выбрать() и Выгрузить() заключается исключительно в том, как эти уже полученные данные будут представлены прикладному коду внутри сервера приложений.
Выбор метода зависит не только от скорости, но и от того, что мы планируем делать с данными дальше. Рассмотрим ситуации, где каждый метод проявляет свои сильные стороны.
Преимущества выборки:
ОбходРезультатаЗапроса.ПоГруппировкам).Преимущества таблицы значений:
НайтиСтроки().Сортировать()), сворачивать (Свернуть()), добавлять или удалять колонки и строки прямо в процессе выполнения кода.Загрузить() у табличных частей документов) принимают в качестве параметра именно таблицу значений.Фирма 1С в своих методических рекомендациях и требованиях к экзамену «1С:Специалист» четко указывает: выгрузка результата запроса в таблицу значений без явной необходимости считается ошибкой. Для выявления последствий подобных ошибок или некорректных доработок можно автоматически сверять бухгалтерские данные между базами 1С.
Система стандартов гласит, что при потенциально неограниченных выборках (например, справочник «Номенклатура» или регистр «Продажи», которые могут расти годами) следует использовать только последовательный обход. Выгрузка в таблицу значений допустима только если:
ТаблицаЗначений.Подводя итог, проанализируем типичный алгоритм выбора метода разработчиком:
Если вам нужно просто прочитать данные и на их основе совершить какие-то действия (создать документы, изменить реквизиты, вывести сообщения) — всегда используйте Выбрать(). Это обеспечит стабильность вашей программы даже при значительном увеличении объема базы данных.
Если же логика задачи требует сложной постобработки данных, которую невозможно реализовать средствами самого SQL-запроса (например, хитрые сортировки или специфические группировки в коде), то выгружайте результат в ТаблицуЗначений, но при этом старайтесь максимально ограничить количество выбираемых данных с помощью условий ГДЕ в запросе.
Помните, что оптимизация использования оперативной памяти — это один из ключевых факторов масштабируемости систем на платформе 1С:Предприятие 8, и в высоконагруженных конфигурациях для этих целей может применяться многопоточная свёртка 1С:ERP.