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