Как правильно получать реквизиты объектов в 1С с помощью БСП и почему это важно для производительности

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

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

Проблема прямого обращения через точку

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


// Неоптимальный способ
Значение = СсылкаНаОбъект.ИмяРеквизита;

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

  1. Избыточный трафик: передача огромного массива данных между СУБД и сервером 1С ради одного значения.
  2. Засорение кэша: считанный объект целиком попадает в кэш объектов. Если вы делаете это в цикле, кэш быстро переполняется, вытесняя действительно нужные данные.
  3. Снижение скорости: десериализация большого объекта занимает значительно больше времени, чем выполнение точечного SQL-запроса.

Решение с помощью БСП: ЗначениеРеквизитаОбъекта

Для решения описанной выше проблемы в БСП предусмотрен модуль ОбщегоНазначения. Рассмотрим подробнее функцию ЗначениеРеквизитаОбъекта. Она позволяет получить ровно одно поле, используя оптимизированный запрос к базе данных.


// Правильный способ получения одного реквизита
Значение = ОбщегоНазначения.ЗначениеРеквизитаОбъекта(СсылкаНаОбъект, "ИмяРеквизита");

Внутри этой функции БСП формирует запрос ВЫБРАТЬ ИмяРеквизита ИЗ Таблица ГДЕ Ссылка = &Ссылка. Это гарантирует минимальную нагрузку на систему.

Получение нескольких реквизитов одновременно

Часто требуется получить не один, а два или три реквизита одного и того же объекта. Если вы трижды вызовете ЗначениеРеквизитаОбъекта, система выполнит три отдельных запроса к базе данных. Чтобы этого избежать, проанализируем функцию ЗначенияРеквизитовОбъекта (обратите внимание на множественное число в названии).

Эта функция принимает список реквизитов (строкой через запятую или массивом) и возвращает Структуру, где ключами являются имена реквизитов. Рассмотрим пример:


// Получение нескольких полей за один запрос
Реквизиты = "ИНН, КПП, НаименованиеПолное";
ДанныеКонтрагента = ОбщегоНазначения.ЗначенияРеквизитовОбъекта(СсылкаНаКонтрагента, Реквизиты);

Если ДанныеКонтрагента.ИНН = "1234567890" Тогда
    // выполняем логику
КонецЕсли;

Выясним причину, по которой этот метод удобнее ручного написания запроса. Функция БСП умеет работать с «путями» через точку. Например, вы можете запросить Владелец.Наименование, и БСП сама корректно обработает левое соединение таблиц в запросе.

Разбор внутреннего устройства функции БСП

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


Функция ЗначенияРеквизитовОбъекта(Ссылка, Знач Реквизиты) Экспорт
    
    // 1. Преобразование строки в массив, если нужно
    Если ТипЗнч(Реквизиты) = Тип("Строка") Тогда
        Реквизиты = СтрРазделить(Реквизиты, ",", Ложь);
    КонецЕсли;
    
    // 2. Формирование текста полей запроса
    ТекстПолей = "";
    Для Каждого Реквизит Из Реквизиты Цикл
        ТекстПолей = ТекстПолей + ?(ПустаяСтрока(ТекстПолей), "", ",") + Реквизит;
    КонецЦикла;
    
    // 3. Динамическое построение запроса
    Запрос = Новый Запрос;
    Запрос.УстановитьПараметр("Ссылка", Ссылка);
    Запрос.Текст = "ВЫБРАТЬ " + ТекстПолей + " ИЗ " + Ссылка.Метаданные().ПолноеИмя() + " ГДЕ Ссылка = &Ссылка";
    
    // 4. Выполнение и заполнение структуры
    Выборка = Запрос.Выполнить().Выбрать();
    Результат = Новый Структура;
    Если Выборка.Следующий() Тогда
        ЗаполнитьЗначенияСвойств(Результат, Выборка);
    КонецЕсли;
    
    Возврат Результат;
КонецФункции

Массовое получение данных для списка объектов

Самая большая ошибка производительности — вызов получения реквизитов внутри цикла по большому массиву ссылок. Это классическая проблема «N+1 запрос».

Проанализируем ситуацию: нам нужно вывести ИНН для 1000 контрагентов в отчете. Если мы вызовем ЗначениеРеквизитаОбъекта в цикле, мы получим 1000 обращений к БД. Для таких случаев в БСП существует функция ЗначенияРеквизитовОбъектов (в конце «в»).

Рассмотрим алгоритм работы:

  1. Вы собираете все нужные ссылки в один Массив.
  2. Передаете этот массив в функцию вместе со списком реквизитов.
  3. Функция возвращает Соответствие (Map), где ключом является Ссылка, а значением — Структура с данными.

// Оптимальная работа с массивом ссылок
МассивСсылок = СписокДокументов.ВыгрузитьКолонку("Ссылка");
ДанныеОбъектов = ОбщегоНазначения.ЗначенияРеквизитовОбъектов(МассивСсылок, "Номер, Дата, СуммаДокумента");

Для Каждого Ссылка Из МассивСсылок Цикл
    ТекущиеДанные = ДанныеОбъектов[Ссылка];
    Если ТекущиеДанные <> Неопределено Тогда
        Сообщить("Документ №" + ТекущиеДанные.Номер);
    КонецЕсли;
КонецЦикла;

Использование кэширования (ПовтИсп)

Иногда одни и те же данные (например, учетная политика организации или базовая валюта) требуются в коде постоянно. Чтобы не дергать базу данных даже оптимизированными запросами, в БСП есть модуль ОбщегоНазначенияПовтИсп.

Функции этого модуля кэшируют результат первого вызова в рамках сеанса. Повторный вызов функции ЗначениеРеквизитаОбъекта из этого модуля вернет данные мгновенно из оперативной памяти сервера.

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

Работа в привилегированном режиме

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

Резюме

Подведем итоги нашего анализа. Для написания качественного кода на платформе 1С 8.3 следует придерживаться следующих правил:

Соблюдение этих простых правил сделает вашу конфигурацию быстрой, масштабируемой и соответствующей стандартам разработки фирмы «1С».

← На главную