В распределенных информационных базах (РИБ) часто возникает ситуация, когда в центральном узле ведется независимый периодический регистр сведений, данные в котором постоянно обновляются и очищаются. При стандартном механизме авторегистрации система фиксирует каждое удаление записи, что приводит к раздуванию файлов обмена: в периферийные базы передается информация не только о новых данных, но и обо всех удаленных «хвостах». Если объем изменений велик, это критически замедляет синхронизацию.
Рассмотрим комплексный подход к решению этой задачи, проанализируем различные методики — от простых манипуляций с регистрацией до сложных программных перехватов — чтобы обеспечить полную перезапись регистра в узлах с минимальным трафиком.
Проанализируем базовый вариант, предложенный в обсуждении. Если мы понимаем, что нам не важна история изменений, а нужно лишь актуальное состояние, первым делом стоит отключить Авторегистрацию для данного регистра в составе Плана обмена.
Разберем алгоритм действий:
Авторегистрация = Запретить.Пример кода для принудительной регистрации всех текущих записей регистра:
// Выбираем все уникальные комбинации измерений (или наборы по основному отбору)
// и регистрируем их для конкретного узла
Запрос = Новый Запрос;
Запрос.Текст =
"ВЫБРАТЬ РАЗЛИЧНЫЕ
| МойРегистр.Период КАК Период
|ИЗ
| РегистрСведений.МойРегистр КАК МойРегистр";
Результат = Запрос.Выполнить();
Выборка = Результат.Выбрать();
Пока Выборка.Следующий() Цикл
Отбор = Новый Структура("Период", Выборка.Период);
ПланыОбмена.ЗарегистрироватьИзменения(УзелСсылка, РегистрыСведений.МойРегистр, Отбор);
КонецЦикла;
Важный нюанс: как справедливо отмечено в обсуждении, простая регистрация «живых» данных не удалит старые записи в периферийной базе. Для очистки на стороне приемника потребуется дополнительная логика (см. Метод 2).
Чтобы гарантировать очистку регистра в периферийной базе без передачи сотен тысяч записей об удалении, можно применить «двухэтапную» схему или передачу пустого набора. Разберем идею с пустым набором:
В одну итерацию обмена мы можем зарегистрировать пустой набор записей (с установленным Замещать = Истина), что приведет к очистке данных в узле-приемнике. В следующую итерацию — передать актуальные данные. Однако более изящным решением будет программная очистка в самой периферии при получении данных.
Если мы используем БСП или стандартный механизм РИБ, мы можем задействовать обработчик ПриЗагрузкеДанныхВУзел. Проанализируем логику:
РегистрыСведений.МойРегистр.СоздатьНаборЗаписей().Записать(Истина);.Выясним, как можно более тонко управлять процессом регистрации изменений, чтобы не перегружать таблицу _ConfigChangeRec. Мы можем оставить авторегистрацию включенной, но «перехватывать» ее в момент записи.
Рассмотрим создание подписки на событие ПередЗаписью для набора записей регистра сведений:
Процедура ПередЗаписьюРегистраНабор(Источник, Отказ, Замещение) Экспорт
// Если запись инициирована обменом данными, ничего не делаем
Если Источник.ОбменДанными.Загрузка Тогда
Возврат;
КонецЕсли;
// Очищаем список получателей, чтобы авторегистрация не сработала стандартно
Источник.ОбменДанными.Получатели.Очистить();
// Здесь можно реализовать свою логику: например, регистрировать только
// изменения для определенных узлов или только для определенных условий
КонецПроцедуры
Если стандартный XML-обмен РИБ по объектам слишком тяжел, рассмотрим альтернативный вариант передачи данных. Вместо регистрации записей регистра напрямую, мы можем использовать технический справочник или документ-контейнер.
Проанализируем шаги этой стратегии:
ПриЗаписи) прописываем код, который распаковывает данные и записывает их в регистр методом Записать(Истина).Это позволяет передать один объект вместо миллиона записей регистра, что колоссально ускоряет процесс загрузки в базу.
Если регистр периодический и для работы периферийных баз не требуется вся история за все время, а достаточно только актуального состояния на текущий момент, мы можем значительно сократить объем выгрузки.
Вместо того чтобы синхронизировать всю таблицу, настроим выгрузку результата виртуальной таблицы СрезПоследних. Посмотрим на пример реализации:
СрезПоследних.ПланыОбмена.ЗарегистрироватьИзменения().Таким образом, в периферийную базу никогда не попадут исторические данные, которые в центральной базе уже не актуальны или удалены.
Подводя итог, можно выделить наиболее эффективный путь для высоконагруженных систем: