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