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

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

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

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

Метод 1: Классический алгоритм сопоставления через запрос

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

Шаг 1. Загрузка данных во временную таблицу

Сначала мы помещаем нашу таблицу значений ДанныеСВебсайта в менеджер временных таблиц. Это позволит нам оперировать данными на стороне СУБД. Важно не забыть проиндексировать поле Сотрудник, так как по нему будет происходить соединение.


МенеджерВТ = Новый МенеджерВременныхТаблиц;
Запрос = Новый Запрос;
Запрос.МенеджерВременныхТаблиц = МенеджерВТ;
Запрос.Текст = "ВЫБРАТЬ * ПОМЕСТИТЬ ВТ_ДанныеСВебсайта ИЗ &ТЗ КАК ТЗ ИНДЕКСИРОВАТЬ ПО Сотрудник";
Запрос.УстановитьПараметр("ТЗ", ДанныеСВебсайта);
Запрос.Выполнить();

Шаг 2. Получение актуальных данных из регистра

Проанализируем текущее состояние регистра сведений АдресаСотрудниковКомпании. Нам нужен срез последних, чтобы понять, изменилось ли что-то по сравнению с тем, что пришло с сайта.

Шаг 3. Сравнение и поиск изменений

Мы выполним запрос, который разделит наши данные на две категории: новые сотрудники (которых нет в регистре) и сотрудники с изменившимися данными. Рассмотрим пример текста такого запроса:


Запрос.Текст = 
"ВЫБРАТЬ
|	ТЗ.Сотрудник,
|	ТЗ.АдресПроживания,
|	ТЗ.ГородПроживания
|ИЗ
|	ВТ_ДанныеСВебсайта КАК ТЗ
|		ЛЕВОЕ СОЕДИНЕНИЕ РегистрСведений.АдресаСотрудниковКомпании.СрезПоследних(&ТекущаяДата, ) КАК Срез
|		ПО ТЗ.Сотрудник = Срез.Сотрудник
|ГДЕ
|	Срез.Сотрудник ЕСТЬ NULL
|	ИЛИ ТЗ.АдресПроживания <> Срез.АдресПроживания
|	ИЛИ ТЗ.ГородПроживания <> Срез.ГородПроживания";

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

В этом запросе условие Срез.Сотрудник ЕСТЬ NULL отбирает новые записи, а сравнение ресурсов (Адрес, Город) — измененные. Проанализируем ситуацию: если данные идентичны, запись в регистр не производится, что экономит ресурсы сервера и объем транзакционного лога.

Метод 2: Запись данных через МенеджерЗаписи

После того как мы получили таблицу только с теми данными, которые действительно нужно обновить или добавить, переходим к записи. При объеме в 1000 строк использование МенеджерЗаписи в цикле вполне допустимо и не вызовет критических задержек.


Для Каждого СтрокаДанных Из РезультатЗапроса Цикл
    МЗ = РегистрыСведений.АдресаСотрудниковКомпании.СоздатьМенеджерЗаписи();
    ЗаполнитьЗначенияСвойств(МЗ, СтрокаДанных);
    МЗ.Период = ТекущаяДата(); // Устанавливаем текущий момент времени для истории
    МЗ.Записать();
КонецЦикла;

Важно помнить: МенеджерЗаписи работает с конкретной записью, определяемой уникальным ключом (в данном случае Период + Сотрудник). Если на ту же секунду уже есть запись, она будет перезаписана. Если нет — создана новая, что и обеспечивает хранение истории.

Метод 3: Современный подход — Режим Слияния (Платформа 8.3.25+)

В последних версиях платформы 1С реализованы расширенные режимы записи наборов данных. Если ваша конфигурация работает на версии 8.3.25 и выше, вы можете использовать РежимЗамещения.Слияние (или Merge).

Этот режим позволяет отправить в базу целый пакет данных. Платформа сама определит: если запись с таким ключом (Период + Измерения) существует — она обновит ресурсы, если нет — добавит новую. Это работает значительно быстрее, чем цикл с менеджером записи.


НаборЗаписей = РегистрыСведений.АдресаСотрудниковКомпании.СоздатьНаборЗаписей();
НаборЗаписей.РасширенныеРежимыЗамещения = Истина;

Для Каждого Строка Из ДанныеСВебсайта Цикл
    НоваяЗапись = НаборЗаписей.Добавить();
    ЗаполнитьЗначенияСвойств(НоваяЗапись, Строка);
    НоваяЗапись.Период = ТекущаяДата();
КонецЦикла;

// Используем режим Слияние для обновления существующих и добавления новых
НаборЗаписей.Записать(РежимЗамещения.Слияние);

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

Оптимизация производительности при больших объемах

Если количество сотрудников вырастет с 1000 до 100 000, стоит применить дополнительные техники оптимизации:

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

Выясним причину, почему разработчики часто боятся циклов. В 1С обращение к базе внутри цикла считается "плохим тоном", но это правило касается в первую очередь запросов (SELECT). Пакетная запись (INSERT/UPDATE) — это всегда компромисс между скоростью и блокировками таблиц. Для 1000 записей МенеджерЗаписи — это "золотая середина", обеспечивающая простоту кода и корректную работу бизнес-логики (обработчиков событий ПередЗаписью и т.д.).

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

← На главную