Какой самый быстрый способ понять, что данные номенклатуры изменились при загрузке?

Программист 1С v8.3 (Управляемые формы) IT и автоматизация бизнеса
← На главную

При реализации механизмов интеграции, когда данные поступают от внешнего поставщика, одной из самых ресурсоемких операций является запись объекта в базу данных. Если номенклатура содержит десятки реквизитов и сотни дополнительных свойств, "слепая" перезапись каждого элемента (даже если данные не менялись) приводит к избыточной нагрузке на сервер, раздуванию транзакционного лога и замедлению работы индексов. В этой статье мы подробно рассмотрим, как максимально быстро определить, изменились ли данные, и стоит ли выполнять метод Записать().

Проблема "слепой" записи и базовые подходы

Рассмотрим стандартную ситуацию: поставщик присылает полный файл номенклатуры, не разделяя ее на новые и измененные позиции. Наша задача — минимизировать количество обращений к базе данных. Основная "дорогая" операция в 1С — это ПолучитьОбъект() и последующая Записать(). Если мы будем выполнять их для каждой строки входящего файла, скорость загрузки будет крайне низкой.

Первый очевидный вариант — пореквизитное сравнение. Мы находим существующую ссылку, получаем объект и сравниваем каждое поле:


Если СпрОбъект.Наименование <> ВходящееНаименование 
   Или СпрОбъект.Артикул <> ВходящийАртикул Тогда
    СпрОбъект.Записать();
КонецЕсли;

Проблема этого метода в том, что для сравнения нам уже пришлось вызвать ПолучитьОбъект(), что занимает значительное время и память. Нам же нужен способ отсечь неизмененные данные еще на этапе запроса или до инициализации тяжелого объекта 1С.

Метод хеширования данных (оптимальный выбор)

Одним из самых эффективных способов является хранение "отпечатка" (хеша) состояния объекта. Разберем этот алгоритм по шагам:

  1. В справочник Номенклатура добавляется дополнительный реквизит ХешДанных (строка, 32 символа для MD5).
  2. При первой загрузке или изменении объекта мы собираем все значимые реквизиты в одну строку или структуру, вычисляем хеш-сумму и сохраняем ее.
  3. При следующей загрузке мы вычисляем хеш входящих данных и сравниваем его с тем, что уже хранится в базе, обычным запросом.

Рассмотрим пример функции для формирования хеша, предложенный участниками обсуждения:


Функция СформироватьХеш(Данные) Экспорт
    // Преобразуем структуру данных в строку XML для стабилизации состава полей
    ДанныеСтрока = ОбщегоНазначения.ЗначениеВСтрокуXML(Данные);
            
    ХешированиеДанных = Новый ХешированиеДанных(ХешФункция.MD5);
    ХешированиеДанных.Добавить(ДанныеСтрока);
    
    // Возвращаем результат без пробелов
    Возврат СтрЗаменить(ХешированиеДанных.ХешСумма, " ", "");
КонецФункции

Важный нюанс: при использовании хеширования критически важна канонизация данных. Если поставщик в JSON-файле поменяет порядок свойств местами, хеш изменится, хотя данные остались прежними. Чтобы этого избежать, перед расчетом хеша необходимо всегда сортировать ключи структуры или поля строки в строго определенном порядке.

Сравнение через промежуточные таблицы (Staging Tables)

Если объем данных исчисляется сотнями тысяч позиций, пообъектная обработка в цикле 1С станет узким местом. В этом случае эффективнее использовать механизмы СУБД. Проанализируем этот алгоритм:

  1. Загрузим все входящие данные "как есть" во временную таблицу или специально созданный вспомогательный справочник (staging-таблица).
  2. Выполним один запрос, который соединит основную таблицу номенклатуры с временной по ключевому полю (например, Артикул или ИдентификаторПоставщика).
  3. В условии запроса ГДЕ укажем сравнение всех значимых полей или хешей.

Пример логики запроса:


ВЫБРАТЬ
    ВременнаяТаблица.СсылкаНаНоменклатуру
ИЗ
    ВременнаяТаблица КАК ВременнаяТаблица
    ВНУТРЕННЕЕ СОЕДИНЕНИЕ Справочник.Номенклатура КАК Номенклатура
    ПО ВременнаяТаблица.СсылкаНаНоменклатуру = Номенклатура.Ссылка
ГДЕ
    (ВременнаяТаблица.Наименование <> Номенклатура.Наименование
    ИЛИ ВременнаяТаблица.Цена <> Номенклатура.Цена
    ИЛИ ВременнаяТаблица.Хеш <> Номенклатура.ХешДанных)

Такой подход позволяет за доли секунды получить список только тех ссылок, которые действительно требуют обновления. Мы полностью исключаем чтение неизмененных объектов из базы в память сервера приложений.

Использование системного реквизита ВерсияДанных

В платформе 1С существует скрытый реквизит ВерсияДанных. Он обновляется автоматически при каждой записи. Хотя он напрямую не поможет сравнить данные с файлом поставщика, его можно использовать для контроля "ручных" изменений.

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

Оптимизация работы со строками и типами

При сравнении данных часто возникают ложные срабатывания из-за различий в форматах. Проанализируем типичные ситуации:

Выбор функции хеширования

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

Итоговые рекомендации

Для достижения максимальной производительности мы рекомендуем комбинированный подход:

  1. Используйте хеширование по алгоритму MD5 для набора значимых реквизитов. Храните этот хеш в индексированном реквизите справочника.
  2. Выполняйте первичный отбор изменений через запрос, сравнивая хеш из файла с хешем в базе.
  3. Применяйте пакетную запись объектов в одной транзакции (например, по 100-500 элементов), чтобы ускорить фиксацию данных в СУБД.
  4. Не забывайте про канонизацию (сортировку полей) перед расчетом хеша, чтобы избежать ложных срабатываний при изменении структуры входящего сообщения.

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

← На главную