К статье
Практический материал

Разработка и Конфигурация · 10 мин

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

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

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

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

Что такое ссылка и что происходит при обращении к её реквизитам

Значение типа «СправочникСсылка», «ДокументСсылка» и аналогичных — это, по сути, идентификатор объекта: уникальный идентификатор (GUID) плюс информация о типе. Сама ссылка не содержит ни наименования, ни кода, ни реквизитов объекта. Пока код работает только со ссылкой — сравнивает её, записывает в реквизит, передаёт в параметр — обращения к данным объекта не происходит.

Как только в коде появляется обращение к реквизиту через точку — например, Контрагент.Наименование или Док.Номер — платформа выполняет «разыменование»: загружает данные объекта из базы. Именно в этот момент срабатывает механизм кэширования: загруженные данные сохраняются в кэше объектов, и последующие обращения к реквизитам той же ссылки обслуживаются из памяти.

Важно понимать, что безопасными «бесплатными» операциями со ссылкой являются сравнение, проверка Пустая(), получение УникальныйИдентификатор() и передача в запрос в качестве параметра. Всё остальное — потенциальное чтение из базы.

Как устроен кэш объектов платформы

Кэш объектов — это внутренняя структура платформы, в которой сохраняются данные объектов, уже прочитанных в текущем сеансе. Ключом служит ссылка, значением — набор реквизитов объекта. Кэш существует и на клиенте, и на сервере, при этом это разные кэши: объект, прочитанный на клиенте, не попадает автоматически в серверный кэш и наоборот.

Кэш привязан к сеансу и времени жизни соответствующего контекста. На сервере данные, прочитанные в рамках одного серверного вызова, могут использоваться повторно в пределах этого вызова; между отдельными серверными вызовами кэш, как правило, не сохраняется, поскольку вызовы могут обслуживаться разными рабочими процессами. На толстом клиенте кэш живёт дольше — в течение работы клиентского приложения.

Кэш объектов не следует путать с кэшем СУБД. Сервер баз данных тоже кэширует страницы данных, и даже «промах» мимо кэша платформы не всегда означает физическое чтение с диска. Но сетевой обмен между сервером 1С и СУБД всё равно происходит, поэтому лишние разыменования остаются источником нагрузки.

Когда разыменование оправдано, а когда становится проблемой

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

Кэш смягчает ситуацию только частично: если в данных много повторяющихся ссылок (например, один и тот же склад или организация), повторные обращения обслужатся из памяти. Но первое чтение каждой уникальной ссылки всё равно идёт в базу, а в реальных данных уникальных контрагентов, номенклатуры и документов обычно много.

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

bsl
// Плохо: разыменование в цикле
Пока Выборка.Следующий() Цикл
    Сообщить(Выборка.Контрагент.Наименование);
КонецЦикла;

// Хорошо: поле получено в запросе
Запрос.Текст = "ВЫБРАТЬ Т.Контрагент.Наименование КАК Наименование ИЗ Документ.Реализация КАК Т";

Практические приёмы эффективной работы со ссылками

Первый приём — перенос всех нужных реквизитов в текст запроса. Если известно, какие поля понадобятся, они должны быть выбраны запросом сразу. Это устраняет разыменование полностью и делает нагрузку предсказуемой: один запрос вместо множества мелких чтений.

Второй приём — использование функции ЗначениеРеквизитаОбъекта() и ЗначенияРеквизитовОбъекта() из Библиотеки стандартных подсистем. Эти функции получают реквизиты через запрос, что управляемее неявного разыменования, особенно когда нужно прочитать один-два реквизита без загрузки всего объекта.

Третий приём — осознанная работа с табличными частями. Обращение ДокументСсылка.Товары загружает табличную часть целиком. Если нужна только сумма по табличной части, выгоднее выполнить запрос с группировкой по таблице Документ.Реализация.Товары, чем загружать все строки в память.

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

Как проверить, что кэш и запросы работают эффективно

Основной инструмент диагностики — замер производительности в конфигураторе (Отладка → Замер производительности). Он показывает, сколько раз и как долго выполнялась каждая строка кода, включая неявные обращения к базе при разыменовании. Большое количество вызовов строки с обращением к реквизиту ссылки — прямой признак проблемы.

Дополнительно полезен технологический журнал: включение событий DBMSSQL или DBPOSTGRS позволяет увидеть фактические запросы к СУБД. Если простая операция порождает сотни одиночных SELECT по первичному ключу — это типичный след разыменования ссылок в цикле.

Контрольные точки

Как проверить результат оптимизации

Количество обращений к СУБД в технологическом журнале
Норма

Один-два запроса на операцию обработки выборки

Тревожный признак

Сотни одиночных SELECT по GUID при обходе цикла

Замер производительности в конфигураторе
Норма

Время сосредоточено в выполнении запроса

Тревожный признак

Время распределено по строкам с обращениями к реквизитам ссылок

Повторное обращение к той же ссылке в сеансе
Норма

Повторное чтение реквизитов выполняется быстро, из кэша

Тревожный признак

Каждое обращение инициирует новый запрос к базе

Ограничения кэша и типичные ошибки

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

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

Типичные ошибки при работе со ссылочными данными
01
Разыменование ссылок внутри цикла по большой выборке — тысячи лишних обращений к СУБД и замедление отчётов и проведения
02
Использование ПолучитьОбъект() только для чтения реквизитов — полная загрузка объекта в память вместо точечного чтения нужных полей
03
Уверенность, что кэш гарантирует актуальность — чтение из кэша может вернуть данные, уже изменённые другим сеансом
04
Обращение к табличной части ссылки ради одной агрегатной суммы — загрузка всех строк вместо одного запроса с группировкой

FAQ

Что быстрее: обращение к реквизиту ссылки или запрос?

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

Очищается ли кэш объектов между серверными вызовами?

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

Почему Ссылка.ПолучитьОбъект() считается плохой практикой для чтения?

Метод создаёт полноценный объект в памяти со всеми реквизитами, табличными частями и механизмами записи. Для чтения пары полей это избыточно и медленнее точечного запроса. ПолучитьОбъект() оправдан только когда объект действительно нужно изменить и записать.

Можно ли программно очистить кэш объектов?

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

Работает ли кэш при обращении к предопределённым элементам?

Обращение к предопределённым элементам через менеджер (например, Справочники.Валюты.USD) обслуживается отдельным кэшем предопределённых значений и выполняется быстро, без чтения объекта из базы при каждом обращении. Это ещё один аргумент использовать предопределённые элементы вместо поиска по коду или наименованию.

Итог

Что важно запомнить

Ссылка — это только идентификатор; обращение к её реквизитам вызывает чтение объекта из базы с сохранением в кэше сеанса. Кэш ускоряет повторные обращения, но не гарантирует актуальность и не спасает от массовых разыменований в циклах. Оптимальный подход — получать нужные поля запросом, а эффективность проверять замером производительности и технологическим журналом.