Как быстро преобразовать результат запроса COM в массив/таблицу значений в 1С?

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

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

Ключевой принцип: минимизация COM-вызовов

Прежде всего, давайте уясним основной принцип, который является краеугольным камнем для производительной работы с COM-объектами в 1С: минимизируйте количество COM-вызовов. Каждый вызов метода или обращение к свойству COM-объекта сопряжено с накладными расходами на межпроцессное или межсерверное взаимодействие. Поэтому вместо того, чтобы многократно обращаться к COM-объекту за каждым отдельным значением или строкой, мы стремимся выполнить как можно больше работы на стороне источника данных (где находится COM-объект), а затем передать результат одним большим "куском" информации.

Метод 1: Пакетная передача данных через сериализацию (XML или JSON)

Наиболее эффективным способом передачи больших объемов данных между базами 1С, особенно через COM, является их сериализация в строковое представление на стороне источника и последующая десериализация на стороне приемника. Это позволяет сократить количество COM-вызовов до минимума – одного для получения сериализованной строки и одного для её обработки.

1.1 XML-сериализация

XML является универсальным форматом для обмена данными и хорошо поддерживается платформой 1С. Мы можем сериализовать объект ТаблицаЗначений (полученный из результата запроса) в XML-строку на стороне удаленной базы и передать эту строку в текущую базу.

  1. На стороне базы-источника (COM-объект):

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

    
    // Предполагаем, что COMОбъект - это ссылка на удаленную базу через COM
    // и у него есть доступ к данным.
    // Пример выполнения запроса на стороне COM-объекта
    // (Этот код выполняется на стороне удаленной базы)
    Запрос = Новый Запрос;
    Запрос.Текст = "ВЫБРАТЬ
    |    Справочник.Номенклатура.Ссылка КАК Номенклатура,
    |    Справочник.Номенклатура.Наименование КАК Наименование
    |ИЗ
    |    Справочник.Номенклатура
    |ГДЕ
    |    Справочник.Номенклатура.ПометкаУдаления = ЛОЖЬ
    |ОГРАНИЧИТЬ 1000"; // Пример запроса
    
    РезультатЗапроса = Запрос.Выполнить();
    ТаблицаЗначенийИзЗапроса = РезультатЗапроса.Выгрузить(); // Выгружаем результат в ТаблицуЗначений
    
    // Сериализация ТаблицыЗначений в XML-строку
    ЗаписьXML = Новый ЗаписьXML;
    ЗаписьXML.УстановитьСтроку(); // Устанавливаем режим записи в строку
    ЗаписьXML.ЗаписатьОбъявлениеXML();
    
    СериализаторXDTO = Новый СериализаторXDTO;
    СериализаторXDTO.Записать(ЗаписьXML, ТаблицаЗначенийИзЗапроса);
    
    СтрокаXML = ЗаписьXML.Закрыть(); // Получаем XML-строку
    
    // Эту СтрокаXML мы возвращаем в основную базу через COM.
    // Например, так:
    // COMОбъект.ПолучитьДанныеXML() возвращает СтрокаXML
    
  2. На стороне основной базы (COM-клиент):

    Получив XML-строку через COM-вызов, мы используем ЧтениеXML и СериализаторXDTO для десериализации обратно в ТаблицаЗначений.

    
    // Получаем XML-строку от COM-объекта (предполагаем, что это уже сделано)
    // Пример: СтрокаXML = COMСоединение.ПолучитьДанныеXML();
    СтрокаXML = "...полученная XML-строка от COM-объекта...";
    
    ЧтениеXML = Новый ЧтениеXML;
    ЧтениеXML.УстановитьСтроку(СтрокаXML);
    
    СериализаторXDTO = Новый СериализаторXDTO;
    ТаблицаЗначений = СериализаторXDTO.Прочитать(ЧтениеXML); // Десериализуем XML в ТаблицуЗначений
    
    // Теперь ТаблицаЗначений готова к использованию в текущей базе
    

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

1.2 JSON-сериализация

JSON (JavaScript Object Notation) является более компактным и часто более быстрым форматом для сериализации/десериализации по сравнению с XML, особенно для простых структур данных. Платформа 1С поддерживает работу с JSON начиная с версии 8.3.7.1759.

  1. На стороне базы-источника (COM-объект):

    Мы преобразуем ТаблицаЗначений в массив структур или соответствий, а затем сериализуем этот массив в JSON-строку.

    
    // Этот код выполняется на стороне удаленной базы
    // Предположим, ТаблицаЗначенийИзЗапроса уже получена
    // (как в примере для XML выше)
    
    // Преобразуем ТаблицуЗначений в массив структур для удобной JSON-сериализации
    МассивДляJSON = Новый Массив;
    Для Каждого СтрокаТЗ Из ТаблицаЗначенийИзЗапроса Цикл
        СтруктураСтроки = Новый Структура;
        Для Каждого КолонкаТЗ Из ТаблицаЗначенийИзЗапроса.Колонки Цикл
            СтруктураСтроки.Вставить(КолонкаТЗ.Имя, СтрокаТЗ[КолонкаТЗ.Имя]);
        КонецЦикла;
        МассивДляJSON.Добавить(СтруктураСтроки);
    КонецЦикла;
    
    // Сериализация массива структур в JSON-строку
    ЗаписьJSON = Новый ЗаписьJSON;
    ЗаписьJSON.УстановитьСтроку();
    ЗаписатьJSON(ЗаписьJSON, МассивДляJSON); // Используем глобальную функцию ЗаписатьJSON
    СтрокаJSON = ЗаписьJSON.Закрыть();
    
    // Эту СтрокаJSON мы возвращаем в основную базу через COM.
    
  2. На стороне основной базы (COM-клиент):

    Получив JSON-строку, мы десериализуем её в массив структур и затем вручную преобразуем его в ТаблицаЗначений.

    
    // Получаем JSON-строку от COM-объекта
    СтрокаJSON = "...полученная JSON-строка от COM-объекта...";
    
    ЧтениеJSON = Новый ЧтениеJSON;
    ЧтениеJSON.УстановитьСтроку(СтрокаJSON);
    
    МассивСтруктурИзJSON = ПрочитатьJSON(ЧтениеJSON); // Используем глобальную функцию ПрочитатьJSON
    
    ТаблицаЗначений = Новый ТаблицаЗначений;
    Если МассивСтруктурИзJSON.Количество() > 0 Тогда
        // Создаем колонки ТаблицыЗначений по ключам первой структуры
        Для Каждого КлючЗначение Из МассивСтруктурИзJSON[0] Цикл
            ТаблицаЗначений.Колонки.Добавить(КлючЗначение.Ключ);
        КонецЦикла;
    
        // Заполняем ТаблицуЗначений данными из массива структур
        Для Каждого СтруктураСтроки Из МассивСтруктурИзJSON Цикл
            НоваяСтрока = ТаблицаЗначений.Добавить();
            Для Каждого КолонкаТЗ Из ТаблицаЗначений.Колонки Цикл
                Если СтруктураСтроки.Свойство(КолонкаТЗ.Имя) Тогда
                    НоваяСтрока[КолонкаТЗ.Имя] = СтруктураСтроки[КолонкаТЗ.Имя];
                КонецЕсли;
            КонецЦикла;
        КонецЦикла;
    КонецЕсли;
    
    // ТаблицаЗначений готова к использованию
    

Преимущества JSON-сериализации: более компактный формат, часто быстрее обрабатывается, хорошо подходит для обмена с веб-сервисами и между различными прикладными решениями 1С.

Метод 2: Использование внутренних функций ЗначениеВСтрокуВнутр() и ЗначениеИзСтрокиВнутр()

Функции ЗначениеВСтрокуВнутр() и ЗначениеИзСтрокиВнутр() позволяют преобразовать практически любое значение 1С во внутреннее строковое представление и обратно. Это кажется очень удобным, но имеет свои особенности и критические ограничения.

  1. На стороне базы-источника (COM-объект):
    
    // Этот код выполняется на стороне удаленной базы
    // Предположим, ТаблицаЗначенийИзЗапроса уже получена
    // (как в примерах выше)
    
    СтроковоеПредставление = ЗначениеВСтрокуВнутр(ТаблицаЗначенийИзЗапроса);
    
    // Эту СтроковоеПредставление мы возвращаем в основную базу через COM.
    
  2. На стороне основной базы (COM-клиент):
    
    // Получаем строковое представление от COM-объекта
    СтроковоеПредставление = "...полученное строковое представление от COM-объекта...";
    
    ТаблицаЗначений = ЗначениеИзСтрокиВнутр(СтроковоеПредставление);
    // ТаблицаЗначений готова к использованию
    

Важное предупреждение: Хотя этот метод выглядит просто, он категорически не рекомендуется для обмена данными между разными информационными базами 1С, особенно если они не являются полными копиями друг друга или не имеют идентичной конфигурации. Строковое представление данных, создаваемое этими функциями, использует внутренние системные идентификаторы, которые уникальны для каждой конкретной информационной базы. При попытке десериализовать такое значение в другой базе могут возникнуть ошибки несоответствия типов, ссылочной целостности или просто неправильное восстановление данных. Эти функции в основном предназначены для сериализации/десериализации внутри одной базы (например, для временного хранения сложных структур в текстовых полях или передачи их через параметры без потери типов). Если перед вами стоит задача точечной миграции объектов между базами с сопоставлением по произвольным полям, а не по уникальным идентификаторам, целесообразно выполнять её с помощью переноса данных между похожими конфигурациями 1С.

Метод 3: Альтернативные механизмы обмена данными

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

  1. Web-сервисы (SOAP) и HTTP-сервисы (REST):

    Эти механизмы предоставляют стандартные, надежные и высокопроизводительные способы обмена данными. Если одна из баз может выступать в роли сервера, предоставляя данные через сервис, а другая — в роли клиента, то это будет значительно более эффективно, чем COM. SOAP использует XML-сообщения, обеспечивая строгую типизацию и надежность, а REST часто использует JSON и является более гибким и легковесным.

    • Преимущества: Независимость от версии платформы (в разумных пределах), возможность обмена через интернет, лучшие возможности для масштабирования и безопасности.
    • Рекомендация: Если вы столкнулись с регулярными обменами больших объемов данных между разными базами, изучите возможность настройки Web- или HTTP-сервисов.
  2. Универсальный обмен данными в формате XML (планы обмена):

    Для обмена данными между типовыми конфигурациями 1С, а также для создания пользовательских правил обмена, существует мощный механизм универсального обмена данными. Он основан на XML-файлах и позволяет описывать правила конвертации объектов с помощью конфигурации "1С:Конвертация данных". Для автоматизации регулярной отправки таких сообщений по расписанию можно настроить автоматический обмен данными между базами 1С.

    • Преимущества: Гибкость, возможность обмена между базами с разной структурой, встроенные механизмы отслеживания изменений (планы обмена).
    • Рекомендация: Отлично подходит для комплексных обменов между различными конфигурациями 1С.

Оптимизация получения данных из запроса

Независимо от выбранного метода передачи, важно максимально эффективно получать данные из запроса на стороне базы-источника:

  1. Метод Выгрузить() для РезультатЗапроса:

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

    
    Запрос = Новый Запрос;
    Запрос.Текст = "...ваш текст запроса...";
    РезультатЗапроса = Запрос.Выполнить();
    ТаблицаЗначенийДляПередачи = РезультатЗапроса.Выгрузить(); // Одно действие, максимально быстрое в рамках 1С
    
  2. Пакетная обработка объектов:

    Если вы не просто получаете данные запросом, а, например, выбираете большое количество ссылочных объектов (справочников, документов), используйте методы пакетной обработки. В 1С существуют механизмы выборок, позволяющие за одно обращение к базе данных получить данные для множества объектов. Например, в версии 8.3.26 появился новый метод ВыбратьПоСсылкам() у менеджеров объектов, который оптимизирует загрузку данных по списку ссылок.

Общие рекомендации по производительности

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

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

Применяя эти методы и принципы, вы сможете значительно повысить производительность обмена данными между базами 1С через COM-соединение, избегая проблем, связанных с медленным построечным обходом и частыми обращениями к COM-объектам. Для контроля правильности переданных сведений и быстрого обнаружения расхождений после завершения обмена запускают автоматическую сверку проводок между базами 1С.

← На главную