При организации обмена данными между двумя базами 1С часто используется механизм COM-соединения. Однако при росте объемов данных многие разработчики сталкиваются с критическим падением производительности. В этой статье мы подробно разберем, почему возникают тормоза при использовании COM, и рассмотрим наиболее эффективные способы передачи ТаблицыЗначений (ТЗ) между базами, которые позволяют ускорить процесс в десятки раз.
Рассмотрим ситуацию, с которой столкнулся автор темы. В коде выполняется цикл по документам, и для каждого документа или строки товаров происходит обращение к свойствам объекта через COM-соединение:
Для каждого Док из Документы Цикл
Док.ИД_УТ = Соединение.string(Док.Ссылка.УникальныйИдентификатор());
Док.Контрагент_ИД_УТ = Соединение.string(Док.Контрагент.УникальныйИдентификатор());
Для каждого Стр из Товары Цикл
Стр.Номенклатура_УТ_ИД = Соединение.string(Стр.Номенклатура.УникальныйИдентификатор());
КонецЦикла;
КонецЦикла;
Главная проблема здесь заключается в явлении, называемом маршалинг. Каждый раз, когда мы пишем Соединение.Метод() или обращаемся к свойству Док.Ссылка, операционная система выполняет контекстное переключение между процессами двух баз. Если у нас 1000 документов и по 10 строк в каждом, программа совершает десятки тысяч «прыжков» между базами. Именно эти обращения, а не сами вычисления, занимают 99% времени.
Проанализируем ситуацию: чтобы ускорить работу, нам нужно придерживаться правила одного вызова. Вместо того чтобы тянуть данные по одной ячейке, мы должны один раз вызвать функцию в удаленной базе, получить весь массив данных и обработать его локально.
Это один из самых старых и простых способов передачи сложных структур данных, таких как ТаблицаЗначений, через COM. Суть метода заключается в том, чтобы превратить таблицу в специальную системную строку на стороне внешней базы, передать эту строку как один объект и восстановить её в основной базе.
Разберем этот процесс по шагам на примере интеграции между конфигурациями:
СправочникСсылка.Номенклатура), их нельзя передавать напрямую, так как они не будут «понятны» другой базе. Ссылки нужно преобразовать в строковые GUID.Посмотрим на пример кода в удаленной базе:
Функция СформироватьДанныеДляПередачи() Экспорт
ТЗ = Новый ТаблицаЗначений;
ТЗ.Колонки.Добавить("НоменклатураGUID");
ТЗ.Колонки.Добавить("Количество");
// ... заполнение ТЗ данными через запрос ...
Для каждого СтрокаТЗ Из ТЗ Цикл
// Используем XMLСтрока для быстрого получения GUID
СтрокаТЗ.НоменклатураGUID = XMLСтрока(СтрокаТЗ.Номенклатура);
КонецЦикла;
Возврат ЗначениеВСтрокуВнутр(ТЗ);
КонецФункции
В основной базе вызываем эту функцию следующим образом:
СтрокаДанных = Соединение.СформироватьДанныеДляПередачи();
МояТЗ = ЗначениеИзСтрокиВнутр(СтрокаДанных);
Важный нюанс: метод ЗначениеВСтрокуВнутр работает максимально эффективно, когда конфигурации идентичны или очень близки. Однако, как подмечено в сообщениях форума, для разных платформ и конфигураций лучше использовать универсальные форматы сериализации.
Если базы имеют разную структуру, надежнее использовать СериализаторXDTO. Этот метод позволяет передать ТаблицуЗначений в виде XML-строки. Рассмотрим, как это реализовать:
На стороне внешней базы (отправителя):
ЗаписьXML = Новый ЗаписьXML;
ЗаписьXML.УстановитьСтроку();
СериализаторXDTO.ЗаписатьXML(ЗаписьXML, ТЗ);
СтрокаXML = ЗаписьXML.Закрыть();
Возврат СтрокаXML;
На стороне приемника мы выполняем обратную операцию. Это позволяет избежать проблем с типами данных, так как XML является универсальным стандартом.
Если вы работаете на платформе 8.3.6 и выше, наиболее производительным и «легким» способом будет использование JSON. Рассмотрим этот вариант, так как он работает быстрее XML и потребляет меньше памяти.
В удаленной базе мы можем выгрузить ТаблицуЗначений в массив структур и сериализовать её:
ЗаписьJSON = Новый ЗаписьJSON;
ЗаписьJSON.УстановитьСтроку();
ЗаписатьJSON(ЗаписьJSON, ТЗ);
Результат = ЗаписьJSON.Закрыть();
Возврат Результат;
В основной базе используем ПрочитатьJSON. Это позволит получить данные практически мгновенно, так как за один вызов через COM-границу передается огромный объем структурированной информации.
При передаче данных через COM нужно учитывать несколько критических моментов, которые упоминались участниками обсуждения:
float, что ведет к потере точности в копейках или весах. Рекомендуется передавать важные числовые данные как строки и преобразовывать их обратно в число уже в целевой базе.Ссылка.УникальныйИдентификатор(), лучше использовать встроенную функцию XMLСтрока(Ссылка). Она работает значительно быстрее и сразу возвращает строковое представление идентификатора.V83.Application используйте V83.COMConnector. Он не запускает графическую оболочку 1С, работает быстрее и потребляет меньше ресурсов сервера.В долгосрочной перспективе, если данные продолжат расти, любое COM-соединение станет узким местом. Рассмотрим рекомендацию из сообщения 11: переход на HTTP-сервисы. В отличие от COM, HTTP-сервисы:
Out of Memory).Резюме: Чтобы ваша программа перестала работать «безобразно медленно», перенесите всю логику формирования таблицы значений на сторону внешней базы. Сформируйте данные одним запросом, упакуйте таблицу в строку (через JSON или XML) и передайте её в основную базу одним вызовом. Это сократит количество обращений через COM с тысяч до одного, что даст колоссальный прирост производительности.