При разработке механизмов интеграции и обмена данными в среде 1С:Предприятие 8 программисты часто сталкиваются с необъяснимым на первый взгляд падением производительности. Типичная ситуация: вы просто регистрируете изменения для объекта, добавляя узел в коллекцию Получатели, а технологический журнал фиксирует тяжелые запросы к СУБД, вычитывающие все реквизиты и все табличные части узла плана обмена. В этой статье мы подробно разберем, почему так происходит, как работает объектная модель платформы и что нужно сделать, чтобы избежать лишней нагрузки на систему.
Рассмотрим стандартный фрагмент кода, который часто встречается в подписках на события или в процедурах ПередЗаписью объектов:
НаборУзлов = ЭлементДанных.ОбменДанными.Получатели;
Для каждого Узел из ВыбранныеУзлы Цикл
НаборУзлов.Добавить(Узел);
КонецЦикла;
Проанализируем ситуацию: переменная Узел содержит ссылку (ПланОбменаСсылка). Казалось бы, добавление ссылки в коллекцию — это чисто адресная операция. Однако в технологическом журнале (ТЖ) мы видим, что в этот момент платформа выполняет SELECT ко всем полям таблицы плана обмена, включая поля неограниченной длины и все вложенные табличные части. Если ваш план обмена "тяжелый" (содержит настройки фильтрации в ТЧ, хранилища значений или длинные текстовые описания), каждая запись объекта начинает занимать секунды вместо миллисекунд.
Выясним причину такого поведения. Когда выполняется метод Добавить() для коллекции ОбменДанными.Получатели, платформа 1С выполняет внутреннюю валидацию. Системе необходимо удостовериться, что передаваемая ссылка действительно принадлежит к типу, который входит в состав этого конкретного плана обмена. Кроме того, проверяется состояние узла и его соответствие правилам регистрации. В объектной технике 1С не реализовано понятие "частичного считывания" — если платформе понадобилось проверить хотя бы одно свойство объекта за пределами того, что хранится в самой ссылке (GUID), она считывает объект целиком.
Рассмотрим подробнее влияние свойства Автозаполнение коллекции НаборУзлов. По умолчанию оно установлено в значение Истина. Это означает, что платформа при записи объекта самостоятельно пытается определить список узлов-получателей, основываясь на составе плана обмена, указанном в метаданных.
Когда мы вручную вызываем НаборУзлов.Добавить(Узел) при включенном автозаполнении, происходит следующее:
Это создает колоссальную нагрузку, особенно если в плане обмена хранятся настройки выгрузки (например, список организаций или складов в табличной части).
Проанализируем структуру вашего плана обмена. Самый эффективный способ борьбы с этой проблемой — проектирование "легких" планов обмена. Существует золотое правило архитектуры 1С: план обмена не должен быть местом хранения настроек.
Если ваш план обмена содержит табличные части с тысячами строк или реквизиты типа ХранилищеЗначения, удалите их. Вынесите все сопутствующие данные в Регистры сведений, где ключом будет ссылка на узел плана обмена. В самом объекте ПланОбмена должны остаться только:
Активен).В этом случае, даже если платформа решит считать объект целиком, запрос к СУБД будет мгновенным, так как объем данных в одной строке таблицы будет минимален.
Посмотрим на альтернативный метод регистрации, который позволяет избежать манипуляций с коллекцией Получатели непосредственно в момент записи объекта. Вместо добавления узлов в ОбменДанными.Получатели, мы можем использовать метод ПланыОбмена.ЗарегистрироватьИзменения().
Рассмотрим пример кода:
// Вместо записи внутри объекта, делаем это после или во внешней обработке
ПланыОбмена.ЗарегистрироватьИзменения(МассивУзлов, СсылкаНаОбъект);
Этот метод работает напрямую с таблицами регистрации изменений (таблицы с префиксом _Chng в БД) и зачастую выполняет меньше проверок, связанных с инициализацией объектного кэша самих узлов. Однако стоит помнить, что этот метод также может инициировать обращения к метаданным, поэтому "легкость" узлов все равно остается приоритетом.
Если логика определения узлов полностью описывается вами программно, попробуйте установить свойство Автозаполнение в значение Ложь. Разберем, как это помогает:
НаборУзлов = ЭлементДанных.ОбменДанными.Получатели;
НаборУзлов.Автозаполнение = Ложь;
Для каждого Узел из ВыбранныеУзлы Цикл
НаборУзлов.Добавить(Узел);
КонецЦикла;
Установка Автозаполнение = Ложь говорит платформе, что ей не нужно проводить сложный анализ состава метаданных и сравнивать результаты с вашим списком. Это может снизить количество неявных обращений к полям объекта узла, хотя и не гарантирует полного отсутствия запросов, так как проверка типа ссылки все равно остается на стороне ядра платформы.
Часто возникает вопрос: "Почему 1С не кэширует узел после первого считывания?". На самом деле, кэширование работает, но в высоконагруженных системах оно может быть неэффективным по нескольким причинам:
Именно поэтому нельзя полагаться на кэш. Единственный надежный способ оптимизации — физическое сокращение объема данных в одной записи плана обмена.
Подведем итог нашему разбору. Поведение платформы, при котором считывается весь объект при обращении к ссылке в контексте планов обмена, является ожидаемым и заложенным в архитектуру 1С. Чтобы ваша система работала быстро, придерживайтесь следующих правил:
ПланыОбмена.ЗарегистрироватьИзменения() вне транзакции основной записи объекта, если это допустимо бизнес-логикой._NodeX_VT...).Соблюдение этих принципов позволит значительно снизить нагрузку на СУБД и обеспечит стабильную работу механизмов синхронизации данных даже в очень крупных информационных базах.