При переходе в разработку на платформе 1С программисты часто сталкиваются с советами коллег из мира C++ или PHP, которые рекомендуют сокращать количество промежуточных переменных для экономии оперативной памяти. Типичный пример спора — способ обработки результата запроса: объявлять ли промежуточную переменную РезультатЗапроса или использовать цепочку вызовов методов в одну строку. Разберем детально, как устроена работа с памятью в платформе 1С:Предприятие, соответствуют ли подобные «микрооптимизации» стандартам разработки и как писать чистый, надежный и производительный код.
Рассмотрим два распространенных варианта написания кода при выполнении запроса и обходе его результатов.
Вариант 1 (рекомендуемый стандартами 1С):
РезультатЗапроса = Запрос.Выполнить();
Если Не РезультатЗапроса.Пустой() Тогда
Выборка = РезультатЗапроса.Выбрать();
Пока Выборка.Следующий() Цикл
// Обработка данных
КонецЦикла;
КонецЕсли;
Вариант 2 (цепочка вызовов):
Выборка = Запрос.Выполнить().Выбрать();
Пока Выборка.Следующий() Цикл
// Обработка данных
КонецЦикла;
Проанализируем технические аспекты каждого подхода с точки зрения расхода памяти, архитектуры платформы, отладки и стандартов разработки.
Выясним, действительно ли создание промежуточной переменной приводит к увеличению потребления оперативной памяти.
РезультатЗапроса создается сервером 1С в любом случае, независимо от того, присвоили мы его явной переменной или вызвали метод по цепочке.Запрос.Выполнить().Выбрать() промежуточный результат запроса удаляется сборщиком мусора сразу после выполнения строки, а в варианте с явной переменной — при выходе из контекста текущей процедуры/функции. Разница в потреблении памяти между этими вариантами измеряется байтами, что на фоне работы сервера СУБД и прикладных данных не оказывает никакого измеримого эффекта на общую производительность.РезультатЗапроса = Неопределено;, а не сомнительные сокращения синтаксиса.Посмотрим на практическую пользу сохранения объекта РезультатЗапроса в отдельную переменную:
РезультатЗапроса.Пустой() отрабатывает быстрее, чем инициализация курсора выборки методом Выбрать(). Если запрос вернул пустой результат, проверка позволяет пропустить создание объекта ВыборкаИзРезультатаЗапроса и не выполнять лишний код цикла.РезультатЗапроса позволяет разработчику в окне «Вычисление выражений» быстро вызвать метод Выгрузить() и визуально проанализировать таблицу с данными. В цепочке вызовов разработчик лишен этой возможности без повторного перезапуска запроса.Запрос.Выполнить(), что существенно упрощает чтение стека вызовов.Разберем еще одну частую ошибку оптимизации — повсеместную выгрузку результата запроса в ТаблицаЗначений вместо использования выборки:
// Неоптимальный подход при простом обходе данных:
ТЗ = Запрос.Выполнить().Выгрузить();
Для Каждого Стр Из ТЗ Цикл
// Обработка строки
КонецЦикла;
Проанализируем последствия такого решения:
ВыборкаИзРезультатаЗапроса работает как потоковый курсор, последовательно считывая строки данных. Это обеспечивает минимальный расход оперативной памяти даже на выборках в сотни тысяч записей.Выгрузить() полностью копирует все данные запроса в оперативную память сервера или клиента, создавая тяжеловесные коллекции строк и колонок. На больших массивах информации такой подход приводит к ошибке «Нехватка памяти».Использование метода Выгрузить() оправдано только тогда, когда над полученными данными требуется выполнять специальные операции: поиск методом Найти(), фильтрацию через НайтиСтроки(), сортировку или группировку методами Свернуть() и Сортировать().
Официальные стандарты разработки фирмы «1С» ставят читаемость, надежность и простоту поддержки кода выше микрооптимизаций синтаксиса. Основные правила работы с запросами:
Если Не РезультатЗапроса.Пустой() Тогда перед созданием выборки.ВыборкаИзРезультатаЗапроса перед ТаблицаЗначений.