Является ли использование функции Строка() в цикле запросом к базе данных и как это влияет на производительность

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

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

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

Механизм работы функции Строка() для ссылочных типов

Рассмотрим ситуацию, когда у нас есть выборка из запроса, содержащая ссылки на элементы справочников или документы. Проанализируем типичный фрагмент кода, вызывающий споры:


Пока Выборка.Следующий() Цикл
    ТекстовоеПредставление = Строка(Выборка.СубконтоДт1);
    // Дальнейшая обработка...
КонецЦикла;

Когда мы вызываем Строка(Выборка.СубконтоДт1), где СубконтоДт1 — это ссылка, платформа должна вернуть текстовое описание объекта (например, наименование номенклатуры или номер и дату документа). Проблема в том, что в самой переменной типа Ссылка содержится только уникальный идентификатор (GUID). Текстовых данных там нет.

Чтобы получить текст, платформа выполняет следующие действия:

  1. Проверяет наличие представления данного объекта в локальном кэше текущего сеанса.
  2. Если в кэше данных нет, платформа генерирует неявный запрос к базе данных. Этот запрос обращается к таблице соответствующего объекта и считывает поля, которые определены в метаданных как «Основное представление» (обычно это Наименование или Код для справочников, Номер и Дата для документов).

Таким образом, использование Строка(Ссылка) внутри цикла — это классический неявный запрос в цикле. С точки зрения экзаменатора на «Специалисте», это грубая ошибка, приводящая к снижению оценки. Даже если кэш помогает избежать повторных запросов для одинаковых ссылок, первое обращение к каждому уникальному элементу все равно породит транзакцию к СУБД.

Различие между явным обращением через точку и функцией Строка()

Важно различать два вида обращений, которые часто путают начинающие разработчики:

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

2. Использование функции Строка(): Строка(Выборка.Субконто). Здесь платформа использует оптимизированный механизм получения только полей представления. Это «легче», чем чтение всего объекта, но все же остается запросом к БД.

Проанализируем ситуацию с составными типами данных, такими как Субконто. Для них ситуация еще сложнее: системе сначала нужно определить тип значения по ссылке, а затем обратиться к соответствующей таблице (Справочник.Номенклатура, Справочник.Контрагенты и т.д.). Это создает дополнительную нагрузку на сервер приложений и СУБД.

Почему такой код встречается в типовых конфигурациях?

Разберем причины, по которым в тиражных решениях от 1С (БУХ, ЗУП, ERP) можно встретить подобные конструкции в модулях печати или небольших обработках:

  1. Объем данных: В печатной форме бухгалтерской справки или корректировки долга обычно содержится от нескольких единиц до нескольких десятков строк. При таком объеме разница в скорости между оптимизированным запросом и функцией Строка() составляет миллисекунды, что незаметно для пользователя.
  2. Универсальность кода: Использование Строка() позволяет писать универсальные алгоритмы, которые работают с любыми типами данных без необходимости динамически менять текст SQL-запроса для получения представлений.
  3. Кэширование: Платформа 1С достаточно эффективно кэширует представления. Если в документе 100 строк, но во всех них указано одно и то же подразделение, реальный запрос к базе для получения строки «Подразделение» выполнится только один раз.

Однако помните: для высоконагруженных систем или при обработке тысяч строк (например, в проведении документов или массовых расчетах) такой подход недопустим.

Как сделать правильно: оптимизация через ПРЕДСТАВЛЕНИЕ() в запросе

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

Вместо того чтобы получать просто ссылку, добавим в запрос виртуальное поле:


Запрос = Новый Запрос;
Запрос.Текст = 
    "ВЫБРАТЬ
    |   ХозрасчетныйДвиженияССубконто.СубконтоДт1 КАК СубконтоСсылка,
    |   ПРЕДСТАВЛЕНИЕ(ХозрасчетныйДвиженияССубконто.СубконтоДт1) КАК СубконтоТекст
    |ИЗ
    |   РегистрБухгалтерии.Хозрасчетный.ДвиженияССубконто КАК ХозрасчетныйДвиженияССубконто
    |ГДЕ
    |   ХозрасчетныйДвиженияССубконто.Регистратор = &Регистратор";

Важный нюанс: Функция ПРЕДСТАВЛЕНИЕ() в языке запросов является «виртуальной». Она не выполняется на стороне SQL-сервера. Платформа 1С сначала получает данные из таблиц, а затем одним эффективным пакетом запрашивает представления для всех уникальных ссылок, полученных в результате запроса. Это на порядок быстрее, чем вызывать Строка() для каждой записи в цикле.

Теперь в цикле обхода выборки мы будем обращаться к уже готовой строке:


Выборка = Запрос.Выполнить().Выбрать();
Пока Выборка.Следующий() Цикл
    // Здесь НЕТ обращения к базе данных, значение уже в памяти
    ТекстовоеПредставление = Выборка.СубконтоТекст; 
КонецЦикла;

Использование инструментов БСП для массового получения представлений

Если вы работаете в современной конфигурации на базе Библиотеки стандартных подсистем (БСП), рассмотрим еще один мощный инструмент — программное получение представлений для массива ссылок. Это особенно полезно, когда ссылки уже получены, но текста для них нет, и вы не хотите или не можете менять текст исходного запроса.

Для этого воспользуемся методом общего модуля:


МассивСсылок = Новый Массив;
// Заполняем массив ссылками, для которых нужны названия
МассивСсылок.Добавить(Ссылка1);
МассивСсылок.Добавить(Ссылка2);

// Получаем соответствие Ссылка -> Представление одним запросом
ТаблицаПредставлений = ОбщегоНазначения.СформироватьПредставленияОбъектов(МассивСсылок);

Для Каждого СтрокаПредставления Из ТаблицаПредставлений Цикл
    Сообщить(СтрокаПредставления.Представление);
КонецЦикла;

Этот метод внутри себя выполняет оптимизированный запрос, минимизируя количество обращений к СУБД. Это лучший выбор для реализации сложной бизнес-логики в реальных проектах.

Подведем итоги и закрепим правила

Проанализировав ситуацию с «запросами в цикле» через строковые функции, мы можем сформулировать следующие рекомендации:

Для подготовки к экзамену «Специалист»:

  1. Никогда не используйте Строка(Ссылка) внутри цикла.
  2. Никогда не обращайтесь через точку к реквизитам (Ссылка.Наименование) в циклах.
  3. Все текстовые данные получайте в запросе через функцию ПРЕДСТАВЛЕНИЕ().

Для реальной разработки:

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

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

← На главную