При формировании начального образа подчиненного узла распределенной информационной базы (РИБ) разработчики и администраторы иногда сталкиваются с критической ошибкой: в созданной подчиненной базе данные документов и их движения рассинхронизируются. Например, в регистре накопления или сведений записи физически присутствуют, но отбор по регистратору указывает на один документ, а в самих строках движений фигурирует ссылка на совершенно другой (обычно предыдущий по выборке) документ. В результате стандартное тестирование и исправление выдает ошибки некорректных регистраторов, нарушается целостность учета, а при записи в подчиненной базе могут возникать ошибки нарушения уникальности индексов.
Разберем детально механизм возникновения данной проблемы и рассмотрим все проверенные способы ее устранения.
Выясним причину такого некорректного поведения. Чаще всего сбой проявляется в версиях платформы линейки 8.3.9 (например, 8.3.9.1850). В этой ветке разработчиками платформы был внедрен внутренний механизм оптимизации выборки наборов записей регистров для ускорения процедуры формирования начального образа.
При работе в клиент-серверном режиме (SQL) этот механизм содержит ошибку управления внутренним буфером: при последовательном переборе документов буфер чтения набора записей перед следующей итерацией не сбрасывается полностью. В момент отправки данных значение Отбор.Регистратор.Значение набора записей уже указывает на текущий выгружаемый документ, но внутри самого набора в коллекции строк остаются данные предыдущего документа. Проанализируем это состояние: если проверить свойства объекта в точке останова обработчика обмена, можно увидеть явное несоответствие между значением отбора набора и реквизитом Регистратор в первой строке набора.
Примечательно, что в файловом варианте информационной базы данный серверный конвейер оптимизации не задействуется, и ошибка не воспроизводится.
Также дополнительным фактором сбоя может выступать наличие не уникальных движений в таблицах исходной базы (повреждение агрегатных таблиц или индексов СУБД), из-за чего при выгрузке на SQL-сервере вылетает исключение дублирования ключей.
Если требуется создать начальный образ на текущей версии конфигурации и платформы без остановки сервера, рассмотрим программный способ исправления. В типовых и доработанных конфигурациях обработка выгрузки выполняется в общем модуле в событии отправки данных подчиненному узлу. Мы можем принудительно перечитать набор записей непосредственно перед сериализацией.
Посмотрим на пример реализации в процедуре-обработчике события:
Процедура ПриОтправкеДанныхПодчиненномуСобытие(Источник, ЭлементДанных, ОтправкаЭлемента, СозданиеНачальногоОбраза) Экспорт
Если СозданиеНачальногоОбраза Тогда
ИмяБазовогоТипа = ОбщегоНазначения.ИмяБазовогоТипаПоОбъектуМетаданных(ЭлементДанных.Метаданные);
Если ИмяБазовогоТипа = ОбщегоНазначения.ИмяТипаРегистрыСведений
ИЛИ ИмяБазовогоТипа = ОбщегоНазначения.ИмяТипаРегистрыНакопления
ИЛИ ИмяБазовогоТипа = ОбщегоНазначения.ИмяТипаРегистрыБухгалтерии
ИЛИ ИмяБазовогоТипа = ОбщегоНазначения.ИмяТипаРегистрыРасчета Тогда
// Сбрасываем некорректный платформенный буфер принудительным чтением из базы
ЭлементДанных.Прочитать();
КонецЕсли;
КонецЕсли;
ПриОтправкеДанныхПодчиненному(ЭлементДанных, ОтправкаЭлемента, СозданиеНачальногоОбраза, Источник);
КонецПроцедуры
Вызов метода Прочитать() обращается напрямую к базе данных и заполняет набор актуальными строками текущего регистратора. Данное решение полностью ликвидирует смещение данных, однако увеличивает общее время создания начального образа на больших объемах информации.
Поскольку ошибка буферизации платформы проявляется только в клиент-серверном режиме работы, самым надежным и быстрым вариантом без модификации конфигурации является выгрузка через файловую версию базы. Разберем этот алгоритм по шагам:
.dt..dt.1Cv8.1CD) переносим на рабочий сервер: загружаем его в новую базу SQL через выгрузку/загрузку .dt либо средствами платформы.Если создание начального образа требуется выполнять регулярно в автоматическом режиме, рекомендуется устранить саму первопричину на уровне платформы:
Рассмотрим альтернативный способ развертывания распределенной базы, исключающий выгрузку огромного массива движений через процедуру создания образа:
ПланыОбмена.ЗарегистрироватьИзменения().В ситуациях, когда создание образа аварийно прерывается ошибками СУБД о нарушении уникальности индексов, необходимо устранить расхождения в исходной базе: