Как ускорить работу функции добавления в очередь выгрузки в 1С?

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

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

Проанализируем основные причины замедления работы платформы 1С:Предприятие 8.3 при массовом добавлении записей в очередь выгрузки и разберем практические способы оптимизации кода.

Выяснение причин низкой производительности при массовой записи

Разберем типичный пример кода, приводящий к критическому падению скорости при попытке сформировать очередь выгрузки:


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

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

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

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

Способ 1. Изменение архитектуры: отложенное (асинхронное) формирование JSON

Самым эффективным решением задачи является разделение оперативного проведения документа и процесса подготовки тяжелых данных для API. Разберем этот подход подробнее:

  1. При проведении документа в регистр сведений очереди записывается минимальный объем данных — только ссылка на изменившийся объект (например, Номенклатура) или документ-основание.
  2. Формирование сложных JSON-строк и сбор дополнительных данных выносится в отдельные регламентные или фоновые задания.
  3. Регламентное задание по расписанию порциями считывает зарегистрированные ссылки, подготавливает пакеты данных с помощью объекта ЗаписьJSON и передает их во внешний сервис.

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

Способ 2. Замена обращений к БД в цикле на пакетные запросы

Если данные необходимо готовить сразу, категорически запрещено делать запросы к СУБД внутри цикла перебора. Рассмотрим, как оптимизировать получение данных с помощью запроса:

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

Способ 3. Порционная запись в регистр сведений с отменой замещения

При добавлении массового объема строк в регистр сведений рекомендуется применять объект НаборЗаписей с установкой флага Замещать = Ложь и производить запись порциями.

Проанализируем пример записи данных порциями по 10 000 элементов:


РазмерПорции = 10000;
Счетчик = 0;

НаборОчереди = РегистрыСведений.ОчередьВыгрузки.СоздатьНаборЗаписей();

Для каждого СтрокаИзДанных Из ТаблицаПодготовленныхДанных Цикл
    ЗаписьОчереди = НаборОчереди.Добавить();
    ЗаписьОчереди.Номенклатура = СтрокаИзДанных.Номенклатура;
    ЗаписьОчереди.ДанныеJSON = СтрокаИзДанных.JSON;
    ЗаписьОчереди.ДатаСоздания = ТекущаяДатаСеанса();
    
    Счетчик = Счетчик + 1;
    
    Если Счетчик % РазмерПорции = 0 Тогда
        НаборОчереди.Записать(Ложь);
        НаборОчереди.Очистить();
    КонецЕсли;
КонецЦикла;

Если НаборОчереди.Количество() > 0 Тогда
    НаборОчереди.Записать(Ложь);
    НаборОчереди.Очистить();
КонецЕсли;

Использование параметра Ложь в методе Записать(Ложь) отключает предварительный поиск и удаление существующих записей регистра по отбору, переводя СУБД в режим прямого добавления строк (INSERT), что ускоряет процедуру в десятки раз.

Способ 4. Оптимизация сериализации JSON

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


ЗаписьJSON = Новый ЗаписьJSON;
ЗаписьJSON.УстановитьСтроку();

// Запись структурированного объекта напрямую без создания лишних коллекций
ЗаписатьJSON(ЗаписьJSON, СтруктураДанных);
СтрокаРезультат = ЗаписьJSON.Закрыть();

Применение замера производительности платформы 1С вместе с оптимизацией структуры выгрузки позволяет сократить время массового формирования очереди с 3–5 часов до нескольких минут.

← На главную