Когда вы сталкиваетесь с задачей переноса нескольких миллионов записей справочника Номенклатура между базами 1С, стандартные подходы часто приводят к катастрофическому падению производительности. Скорость в 5-7 элементов в секунду — это явный признак того, что процесс записи не оптимизирован. Давайте разберем по шагам, как кратно увеличить скорость загрузки и сделать этот процесс стабильным.
Одной из самых частых ошибок является выполнение запроса к базе данных внутри цикла для каждого артикула. При 4,5 миллионах записей каждое новое обращение к Запрос.Выполнить() становится экспоненциально медленнее. Вместо этого, давайте выгрузим все артикулы, уже имеющиеся в базе-приемнике, в оперативную память один раз перед началом загрузки.
Для этих целей используем объект Соответствие или ТаблицаЗначений. Если артикул является уникальным полем, Соответствие обеспечит поиск практически за нулевое время.
// Пример предварительной загрузки артикулов
СписокАртикулов = Новый Соответствие;
Запрос = Новый Запрос("ВЫБРАТЬ Артикул ИЗ Справочник.Номенклатура");
Результат = Запрос.Выполнить().Выбрать();
Пока Результат.Следующий() Цикл
СписокАртикулов.Вставить(Результат.Артикул, Истина);
КонецЦикла;
Запись каждого элемента в отдельной транзакции — это «убийца» производительности, так как на каждый вызов метода Записать() платформа фиксирует изменения на диске. Чтобы ускорить процесс, необходимо использовать транзакции для записи порциями (например, по 1000-5000 позиций).
НачатьТранзакцию();
Счетчик = 0;
Для Каждого СтрокаДанных Из ФайлЗагрузки Цикл
// ... создание элемента ...
НоваяНоменклатура.Записать();
Счетчик = Счетчик + 1;
Если Счетчик % 2000 = 0 Тогда
ЗафиксироватьТранзакцию();
НачатьТранзакцию();
КонецЕсли;
КонецЦикла;
ЗафиксироватьТранзакцию();
При массовой загрузке критически важно отключить все проверки, подписки на события, версионирование и контроль дублей, которые штатно срабатывают при записи интерактивно. Для этого используем свойство объекта ОбменДанными.Загрузка = Истина. Это отсечет огромный пласт фоновых вычислений платформы.
ОбъектНоменклатуры = Справочники.Номенклатура.СоздатьЭлемент();
ОбъектНоменклатуры.ОбменДанными.Загрузка = Истина;
ОбъектНоменклатуры.Записать();
Поскольку 1С по своей природе склонна к однопоточной обработке операций, для миллионов записей стоит применить многопоточность. Разделите массив данных на логические части (например, по алфавиту или по группам) и запустите несколько фоновых заданий одновременно. Это позволит загружать данные параллельно, задействуя все вычислительные мощности вашего сервера.
Если даже при оптимизации кода скорость вас не устраивает, стоит рассмотреть переход на SQL-уровень. Самым быстрым способом является Bulk Insert, который позволяет вставить данные напрямую в таблицу ReferenceXXX. Однако помните, что этот метод требует идеального знания структуры таблиц базы данных и наличия навыков работы с СУБД, так как при нарушении ссылочной целостности база может прийти в негодность.
ПриЗаписи, о которой вы могли забыть.Артикул в конфигурации имеет установленный флаг Индексировать. Без индекса поиск по 4,5 млн записей будет выполняться крайне медленно.Применяя эти методы комплексно — кэширование поиска в памяти, пакетную транзакционную запись и использование флага ОбменДанными.Загрузка — вы сможете сократить время загрузки с нескольких суток до приемлемых значений, измеряемых часами.