Почему функция в вычисляемом поле СКД вызывается дважды и как это исправить?

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

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

Анализируем причины повторных вызовов

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

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

Способ 1: Использование кэширования в общем модуле

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

Для этого выполним следующие действия:

  1. Найдем в дереве метаданных общий модуль, в котором описана функция.
  2. В палитре свойств модуля найдем пункт Повторное использование возвращаемых значений.
  3. Установим значение На время вызова или На время сеанса.

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

Способ 2: Разделение «Выражения» и «Выражения представления»

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

Попробуем следующий алгоритм:

  1. Очистим поле Выражение для данного вычисляемого поля.
  2. Перенесем вызов функции общего модуля в поле Выражение представления.

В такой конфигурации СКД поймет, что для внутренних расчетов это поле использовать не нужно, и вызовет функцию только на этапе формирования визуального представления строки. Это может сократить количество вызовов в два раза.

Способ 3: Оптимизация кода функции и обработка пустых значений

Рассмотрим пример функции, которая часто становится причиной замедления отчета при двойных вызовах. Например, функция получения полного пути иерархии справочника, которую привел автор темы:


Функция ПолучитьСтроку(Ссылка, Наименование) Экспорт
    Родитель = Ссылка.Родитель;
    Пока ЗначениеЗаполнено(Родитель) Цикл
        Наименование = Наименование + "/" + Родитель.Наименование;
        Родитель = Родитель.Родитель;
    КонецЦикла;
    Возврат Наименование;
КонецФункции

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

Во-первых, всегда добавим проверку на пустые значения в начале функции, так как СКД может передавать NULL или Неопределено при расчете итогов или пустых группировок:


Функция ПолучитьСтроку(Ссылка, Наименование) Экспорт
    Если Ссылка = Неопределено Или Ссылка.Пустая() Тогда
        Возврат "";
    КонецЕсли;
    
    // Основная логика
    // ...
КонецФункции

Во-вторых, если задача состоит в выводе иерархии, правильнее будет реализовать это средствами самого запроса в СКД, используя иерархические связи, вместо вызова функций в вычисляемых полях. Это позволит платформе получить все данные одним запросом.

Способ 4: Программная передача данных

Если мы используем сложный расчет, разберем вариант с предварительной подготовкой данных. Вместо того чтобы заставлять СКД вычислять значение для каждой строки «на лету», можно подготовить таблицу значений с уже рассчитанными данными во внешнем коде, а затем передать ее в СКД как внешний набор данных. Это гарантирует, что каждое значение будет вычислено ровно один раз.

Итоги и рекомендации

Подводя итог, можно сказать, что «двойной вызов» — это особенность жизненного цикла данных в компоновке. Чтобы минимизировать негативный эффект:

Соблюдение этих правил позволит сделать ваши отчеты быстрыми и отзывчивыми, даже при работе с большими объемами данных и сложными вычислениями в полях компоновки.

← На главную