Разработка и Конфигурация · 10 мин
Как 1С:Предприятие обращается к ссылочным данным и использует кэш объектов
Как 1С:Предприятие обращается к ссылочным данным, как работает кэш объектов, почему возникают лишние обращения к базе и как оптимизировать код.
Ссылочные типы данных — справочники, документы, планы счетов, планы видов характеристик — являются основой любой конфигурации 1С:Предприятие. Каждое обращение к реквизиту ссылки за пределами её идентификатора означает получение данных объекта из базы, и то, как платформа кэширует эти данные, напрямую влияет на производительность прикладного кода.
Разработчик, который понимает механику кэша объектов, пишет код без лишних обращений к СУБД, грамотно использует запросы вместо «разыменований» в циклах и корректно диагностирует проблемы производительности. Ниже разобрано, что происходит при обращении к ссылке, где хранится кэш, как долго он живёт и какие приёмы помогают его использовать эффективно.
Что такое ссылка и что происходит при обращении к её реквизитам
Значение типа «СправочникСсылка», «ДокументСсылка» и аналогичных — это, по сути, идентификатор объекта: уникальный идентификатор (GUID) плюс информация о типе. Сама ссылка не содержит ни наименования, ни кода, ни реквизитов объекта. Пока код работает только со ссылкой — сравнивает её, записывает в реквизит, передаёт в параметр — обращения к данным объекта не происходит.
Как только в коде появляется обращение к реквизиту через точку — например, Контрагент.Наименование или Док.Номер — платформа выполняет «разыменование»: загружает данные объекта из базы. Именно в этот момент срабатывает механизм кэширования: загруженные данные сохраняются в кэше объектов, и последующие обращения к реквизитам той же ссылки обслуживаются из памяти.
Важно понимать, что безопасными «бесплатными» операциями со ссылкой являются сравнение, проверка Пустая(), получение УникальныйИдентификатор() и передача в запрос в качестве параметра. Всё остальное — потенциальное чтение из базы.
Как устроен кэш объектов платформы
Кэш объектов — это внутренняя структура платформы, в которой сохраняются данные объектов, уже прочитанных в текущем сеансе. Ключом служит ссылка, значением — набор реквизитов объекта. Кэш существует и на клиенте, и на сервере, при этом это разные кэши: объект, прочитанный на клиенте, не попадает автоматически в серверный кэш и наоборот.
Кэш привязан к сеансу и времени жизни соответствующего контекста. На сервере данные, прочитанные в рамках одного серверного вызова, могут использоваться повторно в пределах этого вызова; между отдельными серверными вызовами кэш, как правило, не сохраняется, поскольку вызовы могут обслуживаться разными рабочими процессами. На толстом клиенте кэш живёт дольше — в течение работы клиентского приложения.
Кэш объектов не следует путать с кэшем СУБД. Сервер баз данных тоже кэширует страницы данных, и даже «промах» мимо кэша платформы не всегда означает физическое чтение с диска. Но сетевой обмен между сервером 1С и СУБД всё равно происходит, поэтому лишние разыменования остаются источником нагрузки.
Когда разыменование оправдано, а когда становится проблемой
Единичное обращение к реквизитам ссылки — нормальная практика: например, вывести наименование контрагента в сообщении пользователю. Проблема возникает при массовой обработке: классический антипаттерн — цикл по выборке с обращением к реквизитам ссылочных полей внутри каждой итерации. Если выборка содержит тысячи строк и в каждой разыменовываются две-три ссылки, количество обращений к базе исчисляется тысячами.
Кэш смягчает ситуацию только частично: если в данных много повторяющихся ссылок (например, один и тот же склад или организация), повторные обращения обслужатся из памяти. Но первое чтение каждой уникальной ссылки всё равно идёт в базу, а в реальных данных уникальных контрагентов, номенклатуры и документов обычно много.
Правильная альтернатива — получать все нужные поля непосредственно в запросе через точку в тексте запроса. СУБД выполнит соединение таблиц одним обращением, что на порядки эффективнее серии одиночных чтений.
// Плохо: разыменование в цикле
Пока Выборка.Следующий() Цикл
Сообщить(Выборка.Контрагент.Наименование);
КонецЦикла;
// Хорошо: поле получено в запросе
Запрос.Текст = "ВЫБРАТЬ Т.Контрагент.Наименование КАК Наименование ИЗ Документ.Реализация КАК Т";Практические приёмы эффективной работы со ссылками
Первый приём — перенос всех нужных реквизитов в текст запроса. Если известно, какие поля понадобятся, они должны быть выбраны запросом сразу. Это устраняет разыменование полностью и делает нагрузку предсказуемой: один запрос вместо множества мелких чтений.
Второй приём — использование функции ЗначениеРеквизитаОбъекта() и ЗначенияРеквизитовОбъекта() из Библиотеки стандартных подсистем. Эти функции получают реквизиты через запрос, что управляемее неявного разыменования, особенно когда нужно прочитать один-два реквизита без загрузки всего объекта.
Третий приём — осознанная работа с табличными частями. Обращение ДокументСсылка.Товары загружает табличную часть целиком. Если нужна только сумма по табличной части, выгоднее выполнить запрос с группировкой по таблице Документ.Реализация.Товары, чем загружать все строки в память.
- 1Найдите в циклах обращения к реквизитам через точку от ссылочных полей выборки
- 2Перепишите запрос так, чтобы нужные реквизиты выбирались через точку в тексте запроса
- 3Для единичных чтений замените разыменование на ЗначениеРеквизитаОбъекта() из БСП
- 4Проверьте результат замером производительности до и после изменения
- 5Убедитесь, что логика не зависела от побочных эффектов загрузки объекта
Как проверить, что кэш и запросы работают эффективно
Основной инструмент диагностики — замер производительности в конфигураторе (Отладка → Замер производительности). Он показывает, сколько раз и как долго выполнялась каждая строка кода, включая неявные обращения к базе при разыменовании. Большое количество вызовов строки с обращением к реквизиту ссылки — прямой признак проблемы.
Дополнительно полезен технологический журнал: включение событий DBMSSQL или DBPOSTGRS позволяет увидеть фактические запросы к СУБД. Если простая операция порождает сотни одиночных SELECT по первичному ключу — это типичный след разыменования ссылок в цикле.
Как проверить результат оптимизации
Один-два запроса на операцию обработки выборки
Сотни одиночных SELECT по GUID при обходе цикла
Время сосредоточено в выполнении запроса
Время распределено по строкам с обращениями к реквизитам ссылок
Повторное чтение реквизитов выполняется быстро, из кэша
Каждое обращение инициирует новый запрос к базе
Ограничения кэша и типичные ошибки
Кэш объектов не является механизмом совместного доступа к данным между сеансами. Каждый сеанс имеет собственный кэш, и платформа не рассылает уведомления об изменении объектов. Поэтому в сценариях, где данные могут измениться параллельно другим пользователем, полагаться на ранее прочитанные значения нельзя — особенно при проверках перед записью.
Отдельная ловушка — длительные транзакции, внутри которых код читает реквизиты ссылок. Даже если значения берутся из кэша, логика может строиться на устаревшем снимке данных, что приводит к ошибкам вида «данные были изменены» при записи или к некорректным расчётам.
FAQ
Что быстрее: обращение к реквизиту ссылки или запрос?
Для одного-двух обращений разница незаметна, особенно если объект уже в кэше. Для массовой обработки запрос всегда предпочтительнее: он получает все нужные поля одним обращением к СУБД, тогда как разыменование генерирует отдельное чтение на каждую уникальную ссылку.
Очищается ли кэш объектов между серверными вызовами?
Как правило, да. Серверные вызовы могут обслуживаться разными рабочими процессами, и рассчитывать на сохранение кэша между ними нельзя. Поэтому передача на сервер «прогретых» данных не работает — каждый серверный вызов следует проектировать как самодостаточный.
Почему Ссылка.ПолучитьОбъект() считается плохой практикой для чтения?
Метод создаёт полноценный объект в памяти со всеми реквизитами, табличными частями и механизмами записи. Для чтения пары полей это избыточно и медленнее точечного запроса. ПолучитьОбъект() оправдан только когда объект действительно нужно изменить и записать.
Можно ли программно очистить кэш объектов?
Штатного прикладного метода очистки кэша объектов нет. Если требуются гарантированно актуальные данные, их получают запросом или чтением объекта заново, а не попытками управлять кэшем платформы.
Работает ли кэш при обращении к предопределённым элементам?
Обращение к предопределённым элементам через менеджер (например, Справочники.Валюты.USD) обслуживается отдельным кэшем предопределённых значений и выполняется быстро, без чтения объекта из базы при каждом обращении. Это ещё один аргумент использовать предопределённые элементы вместо поиска по коду или наименованию.
Что важно запомнить
Ссылка — это только идентификатор; обращение к её реквизитам вызывает чтение объекта из базы с сохранением в кэше сеанса. Кэш ускоряет повторные обращения, но не гарантирует актуальность и не спасает от массовых разыменований в циклах. Оптимальный подход — получать нужные поля запросом, а эффективность проверять замером производительности и технологическим журналом.