Как ускорить передачу Таблицы Значений через COM-соединение между базами 1С?

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

При организации обмена данными между двумя базами 1С часто используется механизм COM-соединения. Однако при росте объемов данных многие разработчики сталкиваются с критическим падением производительности. В этой статье мы подробно разберем, почему возникают тормоза при использовании COM, и рассмотрим наиболее эффективные способы передачи ТаблицыЗначений (ТЗ) между базами, которые позволяют ускорить процесс в десятки раз.

Выясняем причину: почему COM-соединение работает медленно

Рассмотрим ситуацию, с которой столкнулся автор темы. В коде выполняется цикл по документам, и для каждого документа или строки товаров происходит обращение к свойствам объекта через COM-соединение:


Для каждого Док из Документы Цикл
   Док.ИД_УТ = Соединение.string(Док.Ссылка.УникальныйИдентификатор());
   Док.Контрагент_ИД_УТ = Соединение.string(Док.Контрагент.УникальныйИдентификатор());
   Для каждого Стр из Товары Цикл
       Стр.Номенклатура_УТ_ИД = Соединение.string(Стр.Номенклатура.УникальныйИдентификатор());
   КонецЦикла;
КонецЦикла;

Главная проблема здесь заключается в явлении, называемом маршалинг. Каждый раз, когда мы пишем Соединение.Метод() или обращаемся к свойству Док.Ссылка, операционная система выполняет контекстное переключение между процессами двух баз. Если у нас 1000 документов и по 10 строк в каждом, программа совершает десятки тысяч «прыжков» между базами. Именно эти обращения, а не сами вычисления, занимают 99% времени.

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

Решение №1: Использование ЗначениеВСтрокуВнутр

Это один из самых старых и простых способов передачи сложных структур данных, таких как ТаблицаЗначений, через COM. Суть метода заключается в том, чтобы превратить таблицу в специальную системную строку на стороне внешней базы, передать эту строку как один объект и восстановить её в основной базе.

Разберем этот процесс по шагам на примере интеграции между конфигурациями:

  1. В базе-источнике (где формируются данные) создаем экспортную функцию.
  2. Внутри функции формируем ТЗ, заполняем её данными.
  3. Важно: если в ТЗ есть ссылки (например, СправочникСсылка.Номенклатура), их нельзя передавать напрямую, так как они не будут «понятны» другой базе. Ссылки нужно преобразовать в строковые GUID.
  4. Сериализуем таблицу в строку.

Посмотрим на пример кода в удаленной базе:


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

В основной базе вызываем эту функцию следующим образом:


СтрокаДанных = Соединение.СформироватьДанныеДляПередачи();
МояТЗ = ЗначениеИзСтрокиВнутр(СтрокаДанных);

Важный нюанс: метод ЗначениеВСтрокуВнутр работает максимально эффективно, когда конфигурации идентичны или очень близки. Однако, как подмечено в сообщениях форума, для разных платформ и конфигураций лучше использовать универсальные форматы сериализации.

Решение №2: Сериализация через XML и XDTO

Если базы имеют разную структуру, надежнее использовать СериализаторXDTO. Этот метод позволяет передать ТаблицуЗначений в виде XML-строки. Рассмотрим, как это реализовать:

На стороне внешней базы (отправителя):


ЗаписьXML = Новый ЗаписьXML;
ЗаписьXML.УстановитьСтроку();
СериализаторXDTO.ЗаписатьXML(ЗаписьXML, ТЗ);
СтрокаXML = ЗаписьXML.Закрыть();
Возврат СтрокаXML;

На стороне приемника мы выполняем обратную операцию. Это позволяет избежать проблем с типами данных, так как XML является универсальным стандартом.

Решение №3: Сериализация в JSON (для современных платформ)

Если вы работаете на платформе 8.3.6 и выше, наиболее производительным и «легким» способом будет использование JSON. Рассмотрим этот вариант, так как он работает быстрее XML и потребляет меньше памяти.

В удаленной базе мы можем выгрузить ТаблицуЗначений в массив структур и сериализовать её:


ЗаписьJSON = Новый ЗаписьJSON;
ЗаписьJSON.УстановитьСтроку();
ЗаписатьJSON(ЗаписьJSON, ТЗ);
Результат = ЗаписьJSON.Закрыть();
Возврат Результат;

В основной базе используем ПрочитатьJSON. Это позволит получить данные практически мгновенно, так как за один вызов через COM-границу передается огромный объем структурированной информации.

Оптимизация работы с типами данных и GUID

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

Архитектурный совет: переход на HTTP-сервисы

В долгосрочной перспективе, если данные продолжат расти, любое COM-соединение станет узким местом. Рассмотрим рекомендацию из сообщения 11: переход на HTTP-сервисы. В отличие от COM, HTTP-сервисы:

  1. Не зависят от разрядности систем (32/64 бит).
  2. Не требуют установки специальных драйверов на сервере.
  3. Позволяют передавать данные порциями (пагинация), что исключает ошибки нехватки памяти (Out of Memory).
  4. Работают через стандартные протоколы, что делает интеграцию более стабильной.

Резюме: Чтобы ваша программа перестала работать «безобразно медленно», перенесите всю логику формирования таблицы значений на сторону внешней базы. Сформируйте данные одним запросом, упакуйте таблицу в строку (через JSON или XML) и передайте её в основную базу одним вызовом. Это сократит количество обращений через COM с тысяч до одного, что даст колоссальный прирост производительности.

← На главную