При интеграции систем 1С 7.7 и 1С 8 нередко возникает задача передачи крупных массивов данных (десятки и сотни тысяч строк). Прямой перебор строк и колонок таблицы значений через OLE Automation приводит к сильному падению производительности: таблица из 100 000 строк может обрабатываться 10–15 минут и дольше. Разберем причины такого поведения и рассмотрим практические способы многократного ускорения выгрузки.
Проанализируем типичный пример кода, в котором выполняется построчное чтение OLE-объекта из 1С 7.7 и заполнение таблицы значений на стороне 1С 8:
ТЗ.ВыбратьСтроки();
Пока ТЗ.ПолучитьСтроку() = 1 Цикл
СтрокаТаблицыЗначений = Номенклатура77.Добавить();
СтрокаТаблицыЗначений.УИД0 = ТЗ.УИД0;
СтрокаТаблицыЗначений.Код0 = СокрЛП(ТЗ.Код0);
СтрокаТаблицыЗначений.Наименование0 = СокрЛП(ТЗ.Наименование0);
СтрокаТаблицыЗначений.Код1 = СокрЛП(ТЗ.Код1);
СтрокаТаблицыЗначений.УИД1 = ?(СокрЛП(ТЗ.УИД1) = "", СокрЛП(ТЗ.УИД1), ТЗ.УИД1);
СтрокаТаблицыЗначений.Наименование1 = СокрЛП(ТЗ.Наименование1);
СтрокаТаблицыЗначений.Код2 = СокрЛП(ТЗ.Код2);
СтрокаТаблицыЗначений.УИД2 = ?(СокрЛП(ТЗ.УИД2) = "", СокрЛП(ТЗ.УИД2), ТЗ.УИД2);
СтрокаТаблицыЗначений.Наименование2 = СокрЛП(ТЗ.Наименование2);
СтрокаТаблицыЗначений.Код3 = СокрЛП(ТЗ.Код3);
СтрокаТаблицыЗначений.УИД3 = ?(СокрЛП(ТЗ.УИД3) = "", СокрЛП(ТЗ.УИД3), ТЗ.УИД3);
СтрокаТаблицыЗначений.Наименование3 = СокрЛП(ТЗ.Наименование3);
СтрокаТаблицыЗначений.Страна = СокрЛП(ТЗ.Страна);
СтрокаТаблицыЗначений.ШтрихКод = СокрЛП(ТЗ.ШтрихКод);
СтрокаТаблицыЗначений.СтавкаНДС = СтавкиНДС[ТЗ.СтавкаНДС];
СтрокаТаблицыЗначений.Цена = ТЗ.Цена;
КонецЦикла;
Выясним причину задержки. В данном цикле к OLE-серверу 1С 7.7 выполняется отдельное обращение за каждым свойством каждой строки: ТЗ.Код0, ТЗ.Наименование0 и так далее. Если в таблице 100 000 строк и 30 колонок, операционная система выполняет более 3 000 000 межпроцессных COM-вызовов (маршалинг данных через интерфейс IDispatch). Накладные расходы на переключение контекста между процессами занимают более 95% всего времени выполнения.
Главное правило оптимизации OLE: количество межпроцессных обращений необходимо сводить к абсолютному минимуму.
Наиболее универсальный и быстрый способ в рамках OLE — перенести всю логику обхода таблицы внутрь 1С 7.7, выгрузить данные в файл на диск и прочитать его целиком в 1С 8. В этом случае по OLE выполняется ровно один вызов процедуры.
Функция ВыгрузитьТЗВФайл(ТЗ, ИмяФайла) Экспорт
ТекстФайла = СоздатьОбъект("Текст");
Разд = Симв(9); // Табуляция
ТЗ.ВыбратьСтроки();
Пока ТЗ.ПолучитьСтроку() = 1 Цикл
Стр = "" + ТЗ.УИД0 + Разд + СокрЛП(ТЗ.Код0) + Разд + СокрЛП(ТЗ.Наименование0) + Разд + ТЗ.Цена;
ТекстФайла.ДобавитьСтроку(Стр);
КонецЦикла;
ТекстФайла.Записать(ИмяФайла);
Возврат ИмяФайла;
КонецФункции
ЧтениеТекста:
ПутьКФайлу = "C:\temp\export_data.txt";
OLE77.ВыгрузитьТЗВФайл(ТЗ77, ПутьКФайлу);
ТекстовыйФайл = Новый ЧтениеТекста(ПутьКФайлу, КодировкаТекста.ANSI);
СтрокаДанных = ТекстовыйФайл.ПрочитатьСтроку();
Пока СтрокаДанных <> Неопределено Цикл
МассивПолей = СтрРазделить(СтрокаДанных, Символы.Таб);
НоваяСтрока = Номенклатура77.Добавить();
НоваяСтрока.УИД0 = МассивПолей[0];
НоваяСтрока.Код0 = МассивПолей[1];
НоваяСтрока.Наименование0 = МассивПолей[2];
НоваяСтрока.Цена = Число(МассивПолей[3]);
СтрокаДанных = ТекстовыйФайл.ПрочитатьСтроку();
КонецЦикла;
ТекстовыйФайл.Закрыть();
УдалитьФайлы(ПутьКФайлу);
Такой подход сокращает время переноса 100 000 строк с 10 минут до 2–4 секунд.
Если данные извлекаются напрямую из справочников или регистров 1С 7.7, наиболее производительным вариантом является полный отказ от запуска OLE Automation в пользу прямого чтения таблиц через COM-объект ADODB.Connection.
Посмотрим на алгоритм работы:
SC..., _1SJOURN, RA...).VFPOLEDB).GetRows() объекта ADODB.Recordset, что обеспечивает моментальную передачу данных в оперативную память 1С 8.Если полученную таблицу необходимо использовать для дальнейшей аналитической обработки в запросе 1С 8, нет необходимости создавать физические таблицы в сторонних СУБД. Заполненный объект ТаблицаЗначений передается напрямую в параметры запроса:
Запрос = Новый Запрос;
Запрос.Текст =
"ВЫБРАТЬ
| Данные77.Код0 КАК Код,
| Данные77.Наименование0 КАК Наименование,
| Данные77.Цена КАК Цена
|ПОМЕСТИТЬ ВТ_Номенклатура77
|ИЗ
| &ТаблицаДанных КАК Данные77
|;
|
|////////////////////////////////////////////////////////////////////////////////
|ВЫБРАТЬ
| ВТ.Код,
| ВТ.Наименование,
| ВТ.Цена
|ИЗ
| ВТ_Номенклатура77 КАК ВТ";
Запрос.УстановитьПараметр("ТаблицаДанных", Номенклатура77);
РезультатЗапроса = Запрос.Выполнить();
Платформа 1С 8 самостоятельно создаст временную таблицу на уровне СУБД пакетной вставкой данных, что обеспечивает максимальную скорость выполнения последующих соединений и фильтраций.