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

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

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

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

Выясняем причину: почему Менеджер Записи нагружает ЖР?

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


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

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

  1. Открывает транзакцию в СУБД.
  2. Записывает (или обновляет) одну строку в таблице регистра.
  3. Фиксирует транзакцию в СУБД.
  4. Формирует отдельное системное событие в журнале регистрации (например, транзакционное событие изменения данных _$Data$_.Update или _$Data$_.New).

Если в вашей таблице 100 000 строк, платформа инициирует 100 000 отдельных транзакций СУБД и создаст 100 000 записей в файле журнала регистрации (1Cv8.lgd). Это порождает колоссальную транзакционную нагрузку и приводит к моментальному раздуванию логов.

Решение №1: Переход на Набор Записей (Рекомендованный стандарт 1С)

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

Когда мы записываем данные через набор, платформа производит запись всей пачки данных в рамках одной транзакции. В результате в журнал регистрации помещается всего одно единственное событие об изменении данных для всего набора, независимо от того, сколько строк (10, 100 или 10 000) в нем содержалось. Это позволяет сократить количество логов в тысячи раз.

Рассмотрим пример того, как переписать исходный код автора на использование набора записей с отбором по ключевому измерению (складу):


ТаблицаОстатков = ПолучитьОстатокСкладов(COMСоединение);

// Создаем пустой набор записей регистра
НаборЗаписей = РегистрыСведений.ИнформативныеОстаткиТоваровПоМагазинам.СоздатьНаборЗаписей();

// Устанавливаем жесткий отбор по измерению, чтобы перезаписать данные только по конкретному складу
НаборЗаписей.Отбор.Магазин.Установить(СкладРЦ);

// Наполняем набор записей в цикле новыми данными
Для каждого Строка из ТаблицаОстатков цикл
    СтрокаГуидНоменклатуры = COMСоединение.String(Строка.Номенклатура.UUID());
    ГуидНоменклатуры = Новый УникальныйИдентификатор(СтрокаГуидНоменклатуры);
    Номенклатура = Справочники.Номенклатура.ПолучитьСсылку(ГуидНоменклатуры);
    
    НоваяЗапись = НаборЗаписей.Добавить();
    НоваяЗапись.Магазин = СкладРЦ;
    НоваяЗапись.Номенклатура = Номенклатура;
    НоваяЗапись.Количество = Строка.Остаток;
КонецЦикла;

// Записываем весь набор за один раз. 
// Параметр "Истина" указывает на необходимость замещения существующих в базе данных записей, подходящих под отбор
НаборЗаписей.Записать(Истина);

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

Решение №2: Программное отключение событий журнала регистрации (С высоким риском!)

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

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


Процедура РегистрироватьСобытияЖурналаРегистрацииПриМассовойЗаписи(Регистрировать) Экспорт
    УстановитьПривилегированныйРежим(Истина);
    
    ИспользованиеСобытия = Новый ИспользованиеСобытияЖурналаРегистрации();
    ИспользованиеСобытия.Использование = Регистрировать; // Истина или Ложь
    
    // Отключаем фиксацию создания новых данных
    УстановитьИспользованиеСобытияЖурналаРегистрации("_$Data$_.New", ИспользованиеСобытия);
    // Отключаем фиксацию изменения существующих данных
    УстановитьИспользованиеСобытияЖурналаРегистрации("_$Data$_.Update", ИспользованиеСобытия);
    
    УстановитьПривилегированныйРежим(Ложь);
КонецПроцедуры

Внимание! Использование данного метода в транзакционных бизнес-процессах крайне опасно по нескольким причинам:

Решение №3: Изменение архитектуры и администрирование системы

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

Часто в регистры сведений пытаются записывать "транзитные" или слишком динамические данные (например, ежеминутные GPS-координаты машин, сырые логи технологических обменов, подробные временные статусы). Запись таких данных штатными средствами 1С перегружает не только ЖР, но и транзакционный лог основной СУБД (MS SQL, PostgreSQL).

Рассмотрим альтернативные системные подходы:

  1. Вынос логов и транзитных данных во внешние СУБД: Для хранения часто обновляемых данных (например, оперативных остатков для интернет-магазина или промежуточных логов) эффективнее использовать внешние быстрые key-value хранилища (такие как Redis) или отдельные базы данных NoSQL. Обращение к ним из 1С можно настроить через HTTP/REST API или посредством механизма внешних источников данных. В этом случае ЖР 1С вообще не будет задействован.
  2. Настройка фильтрации ЖР в Конфигураторе: Проверьте текущие настройки журнала регистрации в Конфигураторе (меню "Администрирование" - "Настройка журнала регистрации"). Если для рабочей базы установлен уровень детализации "Регистрировать все", это избыточно. Для стабильной работы большинства систем достаточно уровня "Ошибки, предупреждения, информация", что отсечет часть технологического мусора.
  3. Регулярное сокращение и разделение файлов ЖР: Настройте регламентные процедуры администрирования. Для старого текстового формата ЖР (файлы .elf) настройте разделение файлов по дням или неделям и архивацию старых периодов. Для нового формата SQLite (.lgd) настройте автоматическое сокращение журнала через планировщик задач операционной системы с использованием штатных консольных утилит 1С или регулярное выполнение команды VACUUM для сжатия базы данных логов.

Подведем итоги

Для того чтобы ваша массовая обработка не приводила к аварийному росту журнала регистрации, всегда придерживайтесь золотого правила разработки в 1С: никогда не выполняйте построчную запись данных через Менеджер Записи в цикле. Перевод алгоритмов на использование объекта НаборЗаписей с установкой точечных отборов решает проблему раздувания ЖР в 95% случаев, ускоряет работу программы в десятки раз и гарантирует бесконфликтную работу пользователей в многопользовательском режиме.

← На главную