Как быстро определить, изменился ли объект 1С при перезагрузке данных?

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

При реализации механизмов регулярного обмена данными или импорта из внешних систем мы часто сталкиваемся с проблемой избыточной записи объектов. Когда в базу загружается 10 000 и более документов, перезапись каждого из них (даже если данные не изменились) создает колоссальную нагрузку на сервер приложений, базу данных и дисковую подсистему. Особенно критично это становится в случаях, когда каждый документ должен быть перепроведен, что инициирует цепочку расчетов в регистрах.

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

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

Проанализируем самый "ленивый", но при этом эффективный способ, заложенный в саму платформу 1С:Предприятие 8. У каждого ссылочного объекта (документа, справочника) существует скрытый реквизит ВерсияДанных. На уровне СУБД (например, MS SQL Server) это поле типа timestamp или rowversion.

Как это работает: платформа автоматически обновляет это значение при любой записи объекта в базу данных. Рассмотрим алгоритм его применения:

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

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

Метод 2: Сериализация в FastInfoset или XML для быстрого сравнения

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


Функция СравнитьОбъекты(Объект1, Объект2)
    // Объект1 - прочитанный из базы (Ссылка.ПолучитьОбъект())
    // Объект2 - сформированный программно из файла загрузки
    
    ЗаписьXML = Новый ЗаписьFastInfoset;
    ЗаписьXML.УстановитьДвоичныеДанные();
    ЗаписьXML.ЗаписатьОбъявлениеXML();
    
    ЗаписатьXML(ЗаписьXML, Объект1, НазначениеТипаXML.Явное);    
    ДанныеДвоичные1 = ЗаписьXML.Закрыть();
    
    ЗаписьXML = Новый ЗаписьFastInfoset;
    ЗаписьXML.УстановитьДвоичныеДанные();
    ЗаписьXML.ЗаписатьОбъявлениеXML();
    
    ЗаписатьXML(ЗаписьXML, Объект2, НазначениеТипаXML.Явное);
    ДанныеДвоичные2 = ЗаписьXML.Закрыть();
    
    Возврат (ДанныеДвоичные1 = ДанныеДвоичные2);
КонецФункции

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

Метод 3: Использование хеш-функций (MD5, SHA256)

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

Разберем этапы реализации с использованием объекта ХешированиеДанных:

  1. Сериализуем объект в JSON (это быстрее, чем XML).
  2. Подаем поток JSON в объект хеширования.
  3. Сравниваем полученный хеш с ранее сохраненным значением.

Функция ПолучитьХешОбъекта(Объект)
    ЗаписьJSON = Новый ЗаписьJSON;
    ПараметрыЗаписиJSON = Новый ПараметрыЗаписиJSON(ПереносСтрокJSON.Нет);
    ЗаписьJSON.УстановитьСтроку(ПараметрыЗаписиJSON);
    СериализаторXDTO.ЗаписатьJSON(ЗаписьJSON, Объект, НазначениеТипаXML.Явное);
    СтрокаJSON = ЗаписьJSON.Закрыть();
    
    Хеширование = Новый ХешированиеДанных(АлгоритмХеширования.MD5);
    Хеширование.Добавить(СтрокаJSON);
    Возврат Строка(Хеширование.ХешСумма);
КонецФункции

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

Метод 4: Оптимизация через ЗначениеВСтрокуВнутр()

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

Метод 5: Прямые запросы vs Обращение "через точку"

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


// ТАК ДЕЛАТЬ НЕЛЬЗЯ ПРИ МАССОВОЙ ЗАГРУЗКЕ
Для Каждого СсылкаИзСписка Из СписокСсылок Цикл
    Если СсылкаИзСписка.СуммаДокумента <> НоваяСумма Тогда
        // ... что-то делаем
    КонецЕсли;
КонецЦикла;

Выясним причину проблемы: при обращении Ссылка.Реквизит платформа неявно считывает весь объект из базы данных (включая все его табличные части!). Для 10 000 документов это приведет к катастрофическому замедлению.

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

Практические советы по оптимизации загрузки

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

Резюме

Для максимально быстрой проверки изменений при загрузке 1С-разработчику следует придерживаться следующей стратегии:

  1. Минимизируйте обращения к базе: Используйте запросы для получения данных существующих объектов пачками, а не по одному.
  2. Для простых объектов: Сравнивайте только ключевые реквизиты, полученные запросом.
  3. Для сложных объектов с ТЧ: Используйте сериализацию в JSON или FastInfoset с последующим вычислением хеша через ХешированиеДанных.
  4. Игнорируйте служебные поля: Перед расчетом хеша или сравнением строк обязательно очищайте поля Автор, ДатаМодификации и другие "шумные" реквизиты, которые не влияют на бизнес-логику документа.

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

← На главную