Как организовать эффективный обмен регистра сведений в РИБ без передачи лишних данных об удалении?

Программист IT и автоматизация бизнеса
← На главную

В распределенных информационных базах (РИБ) часто возникает ситуация, когда в центральном узле ведется независимый периодический регистр сведений, данные в котором постоянно обновляются и очищаются. При стандартном механизме авторегистрации система фиксирует каждое удаление записи, что приводит к раздуванию файлов обмена: в периферийные базы передается информация не только о новых данных, но и обо всех удаленных «хвостах». Если объем изменений велик, это критически замедляет синхронизацию.

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

Метод 1. Отключение авторегистрации и принудительная регистрация «живых» данных

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

Разберем алгоритм действий:

  1. В конфигураторе в свойствах Плана обмена для нужного регистра сведений устанавливаем значение Авторегистрация = Запретить.
  2. Перед началом выгрузки данных (например, в регламентном задании или обработчике перед обменом) программно регистрируем только существующие записи.

Пример кода для принудительной регистрации всех текущих записей регистра:


// Выбираем все уникальные комбинации измерений (или наборы по основному отбору)
// и регистрируем их для конкретного узла
Запрос = Новый Запрос;
Запрос.Текст = 
    "ВЫБРАТЬ РАЗЛИЧНЫЕ
    |   МойРегистр.Период КАК Период
    |ИЗ
    |   РегистрСведений.МойРегистр КАК МойРегистр";

Результат = Запрос.Выполнить();
Выборка = Результат.Выбрать();

Пока Выборка.Следующий() Цикл
    Отбор = Новый Структура("Период", Выборка.Период);
    ПланыОбмена.ЗарегистрироватьИзменения(УзелСсылка, РегистрыСведений.МойРегистр, Отбор);
КонецЦикла;

Важный нюанс: как справедливо отмечено в обсуждении, простая регистрация «живых» данных не удалит старые записи в периферийной базе. Для очистки на стороне приемника потребуется дополнительная логика (см. Метод 2).

Метод 2. Использование «сигнального» объекта или двухэтапного обмена

Чтобы гарантировать очистку регистра в периферийной базе без передачи сотен тысяч записей об удалении, можно применить «двухэтапную» схему или передачу пустого набора. Разберем идею с пустым набором:

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

Если мы используем БСП или стандартный механизм РИБ, мы можем задействовать обработчик ПриЗагрузкеДанныхВУзел. Проанализируем логику:

  1. При начале загрузки пакета в периферийную базу программно очищаем весь регистр: РегистрыСведений.МойРегистр.СоздатьНаборЗаписей().Записать(Истина);.
  2. Далее штатный механизм загрузки XML заполнит регистр новыми данными, пришедшими из центра.

Метод 3. Программное управление регистрацией через подписки на события

Выясним, как можно более тонко управлять процессом регистрации изменений, чтобы не перегружать таблицу _ConfigChangeRec. Мы можем оставить авторегистрацию включенной, но «перехватывать» ее в момент записи.

Рассмотрим создание подписки на событие ПередЗаписью для набора записей регистра сведений:


Процедура ПередЗаписьюРегистраНабор(Источник, Отказ, Замещение) Экспорт
    // Если запись инициирована обменом данными, ничего не делаем
    Если Источник.ОбменДанными.Загрузка Тогда
        Возврат;
    КонецЕсли;

    // Очищаем список получателей, чтобы авторегистрация не сработала стандартно
    Источник.ОбменДанными.Получатели.Очистить();
    
    // Здесь можно реализовать свою логику: например, регистрировать только 
    // изменения для определенных узлов или только для определенных условий
КонецПроцедуры

Метод 4. Оптимизация через транспортные контейнеры (Временные таблицы)

Если стандартный XML-обмен РИБ по объектам слишком тяжел, рассмотрим альтернативный вариант передачи данных. Вместо регистрации записей регистра напрямую, мы можем использовать технический справочник или документ-контейнер.

Проанализируем шаги этой стратегии:

  1. В центральной базе собираем все нужные данные регистра в текстовый файл (JSON/CSV) или сериализуем в двоичные данные.
  2. Помещаем этот файл в реквизит специального технического справочника, который участвует в обмене.
  3. В периферийной базе в модуле этого справочника (в обработчике ПриЗаписи) прописываем код, который распаковывает данные и записывает их в регистр методом Записать(Истина).

Это позволяет передать один объект вместо миллиона записей регистра, что колоссально ускоряет процесс загрузки в базу.

Метод 5. Оптимизация через «Срез последних»

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

Вместо того чтобы синхронизировать всю таблицу, настроим выгрузку результата виртуальной таблицы СрезПоследних. Посмотрим на пример реализации:

  1. Отключаем авторегистрацию.
  2. Создаем регламентное задание, которое раз в сутки (или перед обменом) делает выборку из СрезПоследних.
  3. Для каждой полученной записи выполняем ПланыОбмена.ЗарегистрироватьИзменения().

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

Резюме и рекомендации

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

← На главную