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