Как быстро перенести большую таблицу значений из 1С 7.7 в 1С 8 через OLE?

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

При интеграции систем 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: количество межпроцессных обращений необходимо сводить к абсолютному минимуму.

Решение 1. Промежуточная выгрузка через текстовый файл (CSV / TSV)

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

  1. На стороне 1С 7.7 формируем плоский текстовый файл с разделителями (например, табуляцией):
    
    Функция ВыгрузитьТЗВФайл(ТЗ, ИмяФайла) Экспорт
        ТекстФайла = СоздатьОбъект("Текст");
        Разд = Симв(9); // Табуляция
        
        ТЗ.ВыбратьСтроки();
        Пока ТЗ.ПолучитьСтроку() = 1 Цикл
            Стр = "" + ТЗ.УИД0 + Разд + СокрЛП(ТЗ.Код0) + Разд + СокрЛП(ТЗ.Наименование0) + Разд + ТЗ.Цена;
            ТекстФайла.ДобавитьСтроку(Стр);
        КонецЦикла;
        
        ТекстФайла.Записать(ИмяФайла);
        Возврат ИмяФайла;
    КонецФункции
    
  2. На стороне 1С 8 вызываем экспортную функцию по OLE и считываем данные с помощью объекта ЧтениеТекста:
    
    ПутьКФайлу = "C:\temp\export_data.txt";
    OLE77.ВыгрузитьТЗВФайл(ТЗ77, ПутьКФайлу);
    
    ТекстовыйФайл = Новый ЧтениеТекста(ПутьКФайлу, КодировкаТекста.ANSI);
    СтрокаДанных = ТекстовыйФайл.ПрочитатьСтроку();
    
    Пока СтрокаДанных <> Неопределено Цикл
        МассивПолей = СтрРазделить(СтрокаДанных, Символы.Таб);
        
        НоваяСтрока = Номенклатура77.Добавить();
        НоваяСтрока.УИД0          = МассивПолей[0];
        НоваяСтрока.Код0          = МассивПолей[1];
        НоваяСтрока.Наименование0 = МассивПолей[2];
        НоваяСтрока.Цена          = Число(МассивПолей[3]);
        
        СтрокаДанных = ТекстовыйФайл.ПрочитатьСтроку();
    КонецЦикла;
    
    ТекстовыйФайл.Закрыть();
    УдалитьФайлы(ПутьКФайлу);
    

Такой подход сокращает время переноса 100 000 строк с 10 минут до 2–4 секунд.

Решение 2. Прямое чтение базы 1С 7.7 через ADO

Если данные извлекаются напрямую из справочников или регистров 1С 7.7, наиболее производительным вариантом является полный отказ от запуска OLE Automation в пользу прямого чтения таблиц через COM-объект ADODB.Connection.

Посмотрим на алгоритм работы:

  1. Для SQL-версии 1С 7.7 на стороне 1С 8 открывается прямое подключение к MS SQL Server и выполняется запрос к таблицам (SC..., _1SJOURN, RA...).
  2. Для DBF-версии подключение выполняется через OLE DB провайдер (например, VFPOLEDB).
  3. Полученный результат выгружается в массив через метод GetRows() объекта ADODB.Recordset, что обеспечивает моментальную передачу данных в оперативную память 1С 8.

Передача таблицы значений во временные таблицы запроса 1С 8

Если полученную таблицу необходимо использовать для дальнейшей аналитической обработки в запросе 1С 8, нет необходимости создавать физические таблицы в сторонних СУБД. Заполненный объект ТаблицаЗначений передается напрямую в параметры запроса:


Запрос = Новый Запрос;
Запрос.Текст = 
    "ВЫБРАТЬ
    |    Данные77.Код0 КАК Код,
    |    Данные77.Наименование0 КАК Наименование,
    |    Данные77.Цена КАК Цена
    |ПОМЕСТИТЬ ВТ_Номенклатура77
    |ИЗ
    |    &ТаблицаДанных КАК Данные77
    |;
    |
    |////////////////////////////////////////////////////////////////////////////////
    |ВЫБРАТЬ
    |    ВТ.Код,
    |    ВТ.Наименование,
    |    ВТ.Цена
    |ИЗ
    |    ВТ_Номенклатура77 КАК ВТ";

Запрос.УстановитьПараметр("ТаблицаДанных", Номенклатура77);
РезультатЗапроса = Запрос.Выполнить();

Платформа 1С 8 самостоятельно создаст временную таблицу на уровне СУБД пакетной вставкой данных, что обеспечивает максимальную скорость выполнения последующих соединений и фильтраций.

← На главную