При выполнении объемных обработок или межбазового обмена данными разработчики часто сталкиваются со ситуацией, когда процесс занимает 8–10 часов, при этом загрузка процессора, диска и оперативной памяти не превышает 10–15%. Рассмотрим, почему так происходит, имеет ли смысл переводить базу данных из файлового режима в клиент-серверный (MS SQL Server / PostgreSQL) и как существенно сократить время выполнения задачи.
Проанализируем ситуацию, когда система загружена лишь на малую часть своей мощности. Главная причина кроется в специфике работы технологии COM Connector и структуре алгоритма обработки:
COMОбъект создает системный вызов передачи данных между процессами. Если алгоритм выполняет обращения в цикле, 90% времени процессор просто ожидает ответа от стороннего процесса, не нагружая вычислительные ядра.Выясним, даст ли переход на клиент-серверный режим прирост скорости в данном сценарии:
Файловый режим показывает высокую скорость при одиночной последовательной записи на быстрых накопителях (SSD), особенно если размер базы небольшой и умещается в кэш оперативной памяти. Однако при приближении размера таблиц к критическому пределу (4 ГБ на таблицу) файловый движок начинает испытывать проблемы с адресацией и производительность резко падает.
Клиент-серверный режим (SQL) значительно опережает файловый при выполнении сложных выборок, группировок, обработке больших объемов данных и параллельной работе пользователей. Однако сам по себе переход на SQL не исправит задержки, вызваные частыми обращениями через COM. Если ключевое узкое место — межпроцессный обмен, SQL-версия покажет схожие результаты по времени.
Разберем по шагам, какие технические решения позволяют сократить время работы алгоритма с 8 часов до нескольких десятков минут.
Вместо того чтобы искать сопутствующие элементы справочников в базе-приемнике через отдельные запросы, проанализируем возможность конструирования ссылок по уникальному идентификатору (GUID). Это позволяет сразу записать ссылку в реквизит документа, не выполняя чтение объекта из базы:
// Формирование ссылки на элемент по известному GUID без обращения к базе
ЗначениеGUID = Новый УникальныйИдентификатор(СтрокаGUID);
СсылкаКонтрагент = Справочники.Контрагенты.ПолучитьСсылку(ЗначениеGUID);
// Присвоение ссылки реквизиту объекта
НовыйДокумент.Контрагент = СсылкаКонтрагент;
При массовой записи объектов необходимо группировать операции в транзакции и отключать выполнение лишней бизнес-логики с помощью свойства ОбменДанными.Загрузка. Это избавляет систему от постоянных сбросов журнала на диск и выполнения лишних подписок на события.
Счетчик = 0;
НачатьТранзакцию();
Для Каждого СтрИз ДанныеДляЗагрузки Цикл
ДокОбъект = СтрИз.Ссылка.ПолучитьОбъект();
ДокОбъект.ОбменДанными.Загрузка = Истина;
ДокОбъект.Записать(РежимЗаписиДокумента.Запись);
Счетчик = Счетчик + 1;
Если Счетчик % 1000 = 0 Тогда
ЗафиксироватьТранзакцию();
НачатьТранзакцию();
КонецЕсли;
КонецЦикла;
ЗафиксироватьТранзакцию();
Поскольку однопоточная обработка загружает процессор лишь на 10%, рассмотриваем вариант разделения задачи на независимые потоки. Для этого можно запустить несколько параллельных фоновых заданий или отдельных сеансов 1С:
Параллельное выполнение позволяет загрузить все доступные ядра процессора и ресурсы дисковой подсистемы, сокращая общее время выполнения пропорционально количеству потоков.