Что делает платформа 1С, когда код обращается к ссылке через точку

· 10 мин

Содержание

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

Типичная картина: обработка перебирает 5 000 документов, у каждого берёт Ссылка.Контрагент.Наименование, и выполняется не 3 секунды, а 4 минуты. Причина почти всегда одна: работа со ссылочными данными идёт через точку, а не через выборку. Механизм кэширования в 1С:Предприятии 8.3 здесь не спасает: кэш объектов ускоряет повторное чтение того же объекта, а не тысячи разных.

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

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

База подключается в тот момент, когда от ссылки требуют содержимое.

Какие операции читают базу, а какие нет

ОперацияЧтение из базы
Ссылка = Другая (сравнение)нет
Ссылка.Пустая(), ЗначениеЗаполнено(Ссылка)нет
Ссылка.УникальныйИдентификатор()нет
Ссылка.Наименование, Ссылка.Контрагент.ИННда, объект целиком
Ссылка.ПолучитьОбъект()да, объект целиком, создаётся новый экземпляр
вывод ссылки в поле формы или в строкуда, для получения представления
запрос с выбором полейда, только выбранные поля

Цепочка через точку

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

Длинные цепочки через точку внутри цикла — главный источник медленных обработок и проведения. На 10 строках это незаметно, на 10 000 — минуты.

Чем «битая» ссылка отличается от пустой

Пустая ссылка — нулевой идентификатор, в базу за ней платформа не ходит. Битая ссылка указывает на объект, которого в базе нет (удалён напрямую, не перенесён при обмене). В форме она видна как <Объект не найден>, а ПолучитьОбъект() вернёт Неопределено. Проверяйте результат перед использованием, иначе получите ошибку при обращении к полю.

Уровни кэширования в 1С: что, где и сколько живёт

Слово «кэш» в 1С означает несколько разных механизмов. Их часто путают, и отсюда советы вроде «почистите кэш, и проведение ускорится».

МеханизмЧто хранитГде живётКак сбросить
Кэш объектовданные объектов, прочитанных по ссылкев памяти сеанса (на сервере — в рабочем процессе)сам, по времени и при изменении версии объекта
Повторно используемые значениярезультаты функций общих модулей с флагом повторного использованияна время вызова или сеанса, на клиенте или сервереОбновитьПовторноИспользуемыеЗначения()
Кэш метаданных клиентафайлы конфигурации, формы, картинкикаталоги пользователя в профиле Windowsключ запуска /ClearCache или удаление каталогов кэша
Кэш СУБДстраницы данных и планы запросовсервер СУБДсредствами СУБД, из 1С не управляется

Кэш объектов

Когда код прочитал объект по ссылке, платформа сохраняет его данные в памяти сеанса. Повторное обращение к тому же объекту в течение короткого времени берёт данные оттуда, без запроса к СУБД.

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

Повторно используемые значения

Это кэш, которым управляет разработчик. У общего модуля в свойствах есть параметр «Повторное использование возвращаемых значений»:

  • 🔹 Не использовать — функция выполняется при каждом вызове.
  • 🔹 На время вызова — результат живёт, пока выполняется текущий серверный вызов.
  • 🔹 На время сеанса — результат живёт дольше, но платформа может удалить его по времени или при нехватке памяти.

В такие модули выносят то, что почти не меняется: настройки учёта, значения констант, параметры организации. В типовых конфигурациях это модули с окончанием ПовтИсп и ПовтИспКлиент.

Возвращайте из таких функций неизменяемые значения: ФиксированнаяСтруктура, ФиксированныйМассив, ФиксированноеСоответствие. Если вернуть обычную структуру и кто-то изменит её в вызывающем коде, «испорченное» значение получат все следующие вызовы в сеансе.

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

Кэш метаданных клиента

Это то, что чистят ключом /ClearCache в строке запуска 1cv8.exe. Он хранит описание конфигурации на компьютере пользователя и влияет на старт программы, открытие форм и странные ошибки после обновления. На скорость чтения данных из базы он не влияет.

Как читать ссылочные данные без лишней нагрузки

Правило простое: нужно одно-два поля — не читайте объект. Нужен объект для изменения и записи — читайте объект.

Способы получить значения реквизитов

СпособЧто читаетсяКогда применять
Ссылка.Реквизитвесь объектразово, вне циклов, в простом коде
ОбщегоНазначения.ЗначениеРеквизитаОбъекта(Ссылка, "ИНН")одно поле через запроснужен один реквизит одного объекта
ОбщегоНазначения.ЗначенияРеквизитовОбъекта(Ссылка, "ИНН, КПП")несколько полей одного объектанужны 2-5 полей
один запрос по списку ссылоктолько нужные поля всех объектовобработка массива, проведение, отчёты
Ссылка.ПолучитьОбъект()весь объектбудете менять и записывать

Функции ОбщегоНазначения есть в конфигурациях на Библиотеке стандартных подсистем: БП 3.0, ЗУП 3.1, УТ 11 и других типовых. В самописной конфигурации без БСП запрос пишется вручную.

Пример: убрать обращение через точку из цикла

Медленно:

Для Каждого Документ Из МассивДокументов Цикл
    ИНН = Документ.Контрагент.ИНН;
    // ...
КонецЦикла;

Быстро: один запрос на весь массив.

Запрос = Новый Запрос;
Запрос.Текст =
"ВЫБРАТЬ
|    Реализация.Ссылка КАК Документ,
|    Реализация.Контрагент.ИНН КАК ИНН
|ИЗ
|    Документ.РеализацияТоваровУслуг КАК Реализация
|ГДЕ
|    Реализация.Ссылка В (&МассивДокументов)";
Запрос.УстановитьПараметр("МассивДокументов", МассивДокументов);

ИННПоДокументам = Новый Соответствие;
Выборка = Запрос.Выполнить().Выбрать();
Пока Выборка.Следующий() Цикл
    ИННПоДокументам.Вставить(Выборка.Документ, Выборка.ИНН);
КонецЦикла;

Дальше цикл берёт ИНН из соответствия. Вместо тысяч чтений объектов — один запрос.

Не выполняйте запрос внутри цикла по строкам. «Запрос в цикле» так же медленен, как точка в цикле: каждое выполнение — отдельное обращение к СУБД.

Ссылочные поля в запросах: где прячутся соединения

В языке запросов точка тоже работает, но иначе. Реализация.Контрагент.ИНН в запросе платформа превращает в левое соединение с таблицей справочника. Одно такое разыменование — нормально. Проблемы начинаются с составных типов.

Составной тип: соединение с каждой таблицей

Поле Регистратор у регистра может ссылаться на десятки видов документов. Запрос Остатки.Регистратор.Дата заставит платформу соединиться с таблицей каждого документа из состава типа. Запрос формально короткий, а план выполнения — огромный.

Ограничьте тип явно:

ВЫРАЗИТЬ(Движения.Регистратор КАК Документ.РеализацияТоваровУслуг).Дата

Для дат регистраторов вообще не нужно разыменование: у таблиц регистров есть поле Период.

Представления ссылок

Если в результате запроса нужна строка для вывода, а не ссылка, используйте ПРЕДСТАВЛЕНИЕ(Поле) или ПРЕДСТАВЛЕНИЕССЫЛКИ(Поле). Иначе представление будет получено уже после запроса, при выводе, отдельными чтениями.

Чек-лист запроса со ссылками

Проверка запроса перед выпуском
Выполнено: 0 / 5

Блокировки и одновременный доступ к объектам

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

Три вида защиты

МеханизмКак работаетГде применяется
Оптимистическая блокировкапри записи сравнивается версия данных объекта; если её изменили в другом сеансе, запись отменяется с ошибкойавтоматически при записи объекта
Пессимистическая (объектная) блокировкаОбъект.Заблокировать() или открытие формы на редактирование не дают другим сеансам изменить объектинтерактивное редактирование
Управляемая блокировка данныхБлокировкаДанных внутри транзакции, режимы «Разделяемый» и «Исключительный»проведение, контроль остатков

Пример: контроль остатков при проведении

Перед чтением остатков внутри транзакции проведения ставится исключительная блокировка на нужные записи регистра:

Блокировка = Новый БлокировкаДанных;
ЭлементБлокировки = Блокировка.Добавить("РегистрНакопления.ТоварыНаСкладах");
ЭлементБлокировки.Режим = РежимБлокировкиДанных.Исключительный;
ЭлементБлокировки.ИсточникДанных = Товары;
ЭлементБлокировки.ИспользоватьИзИсточникаДанных("Номенклатура", "Номенклатура");
Блокировка.Заблокировать();

Здесь Товары — таблица значений с колонкой Номенклатура. После блокировки остатки читаются запросом, и два документа одновременно не спишут одну и ту же единицу товара.

Ожидание и взаимоблокировки

  • 🔒 Если блокировку держит другой сеанс, ваша транзакция ждёт. Не дождавшись в пределах таймаута, она завершается ошибкой блокировки.
  • 🔁 Взаимоблокировка — когда два сеанса ждут друг друга. Частая причина: разный порядок блокировки ресурсов, сначала разделяемая, потом исключительная блокировка того же ресурса.
  • ⏳ Чем дольше транзакция, тем дольше держатся блокировки. Не вызывайте внутри неё внешние сервисы и не показывайте вопросы пользователю.

Ссылки в управляемом приложении: клиент, сервер, вызовы

В управляемом приложении клиент не работает с базой. В тонком и веб-клиенте ссылку можно хранить и передавать, но обращение через точку к её реквизитам на клиенте недоступно: код вида Объект.Контрагент.ИНН в процедуре &НаКлиенте не пройдёт проверку.

Каждый переход на сервер — это сетевой вызов. Через интернет он стоит десятки или сотни миллисекунд, и это заметно пользователю.

Как сократить серверные вызовы

  1. Собирайте всё нужное за один вызов: функция на сервере возвращает структуру с полями, а не вызывается три раза за три значения.
  2. Используйте &НаСервереБезКонтекста, если серверу не нужна форма. Тогда данные формы не передаются туда и обратно.
  3. Для редко меняющихся значений на клиенте заведите клиентский общий модуль с повторным использованием на время сеанса. Первый вызов сходит на сервер, следующие возьмут значение из клиентского кэша.
  4. В обработчиках ПриИзменении реквизитов формы считайте, сколько раз сработает сервер при вводе строки табличной части. Один вызов на строку при вставке 200 строк из буфера — 200 вызовов.

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

Данные формы и объект

Форма документа хранит не объект, а его копию в виде данных формы. РеквизитФормыВЗначение("Объект") на сервере превращает их в объект, ЗначениеВРеквизитФормы() возвращает обратно. Это не чтение из базы, а преобразование, но оно не бесплатное для документа с тысячами строк. Не делайте его в каждом серверном вызове без нужды.

Как найти узкое место: замеры и технологический журнал

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

Инструменты по порядку

  1. Замер производительности в конфигураторе. Запустите отладку, включите замер через меню отладки, выполните медленную операцию. Отчёт покажет строки кода с процентом времени и числом выполнений. Строка Ссылка.Реквизит с 5 000 выполнений и 70% времени — ваш кандидат.
  2. Технологический журнал. Настраивается файлом logcfg.xml на сервере 1С. События SDBL и DBMSSQL (или DBPOSTGRS) показывают запросы и их длительность, TLOCK, TTIMEOUT, TDEADLOCK — управляемые блокировки, ожидания и взаимоблокировки.
  3. Оценка производительности из БСП. Ключевые операции и показатель APDEX показывают, какие действия пользователей стали медленнее со временем.
  4. Средства СУБД. Планы запросов и ожидания на сервере базы. Помогают, когда медленный один конкретный запрос.

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

Признаки проблем со ссылочными данными

Диагностика: выберите симптом

Частые вопросы

Можно ли вручную очистить кэш объектов из кода?
Нет, отдельной команды для этого нет. Платформа сама сверяет версию объекта и перечитывает его. Если нужны точные данные, читайте их запросом, а в транзакции — после управляемой блокировки.
Сбрасывает ли ключ /ClearCache повторно используемые значения?
Нет. Он чистит кэш метаданных на компьютере пользователя. Повторно используемые значения живут в памяти сеанса и сбрасываются при новом сеансе или вызовом ОбновитьПовторноИспользуемыеЗначения().
Ускорит ли перезапуск рабочих процессов сервера 1С работу базы?
Иногда временно, если процесс разросся по памяти. Причину в коде это не устраняет. Перезапуск оборвёт сеансы пользователей на этом процессе, поэтому делайте его вне рабочего времени.
Читает ли ПолучитьОбъект() данные из кэша объектов?
Метод создаёт новый экземпляр объекта, который можно менять и записывать. Для записи платформа всё равно сверит версию данных, поэтому изменения из другого сеанса не будут молча перезаписаны.
Почему значение из модуля ПовтИсп не обновилось после изменения константы?
Кэш на время сеанса держит старое значение. Вызовите ОбновитьПовторноИспользуемыеЗначения() после записи настройки или попросите пользователей перезайти.