При организации интеграции между 1С и внешними базами данных (СУБД SQL, WMS, CRM-системами) часто требуется передавать идентификаторы ссылочных объектов не в виде внутренних типов 1С или шестнадцатеричных представлений, а в виде стандартных строковых GUID (UUID по стандарту RFC 4122 формата 00000000-0000-0000-0000-000000000000). Построчное получение таких данных через COM-соединение или функциями вроде XMLСтрока() приводит к катастрофическому падению производительности на больших объемах данных. Разберем основные причины медленной работы и рассмотрим эффективные варианты ускорения процесса выгрузки.
Проанализируем, почему типовые подходы работают медленно:
Выборка.Следующий(), Выборка.Ссылка, Выборка.Код), на каждое обращение к реквизиту тратится время на сетевой/системный вызов между процессами.СериализаторXDTO в XML-строку целиком загружает структуру документа в оперативную память, создавая чрезмерную нагрузку на сборщик мусора и приводя к утечкам памяти при отсутствии явного закрытия дескрипторов потоков.INSERT на каждую строку многократно нагружает транзакционный журнал СУБД.Самый простой и надежный способ — выполнить всю выборку, добавление колонок и строковое приведение идентификаторов непосредственно на стороне базы 1С за один вызов, избегая межпроцессных обращений по COM в цикле.
Рассмотрим пример кода на платформе 1С:
Процедура ПолучитьТаблицуУИД()
Запрос = Новый Запрос;
Запрос.Текст =
"ВЫБРАТЬ
| РеализацияТоваровУслуг.Ссылка КАК Док,
| РеализацияТоваровУслуг.СуммаДокумента КАК СуммаДокумента,
| РеализацияТоваровУслуг.Номер КАК Номер
|ИЗ
| Документ.РеализацияТоваровУслуг КАК РеализацияТоваровУслуг";
Таб = Запрос.Выполнить().Выгрузить();
Таб.Колонки.Добавить("UID", Новый ОписаниеТипов("Строка", , Новый КвалификаторыСтроки(36)));
Для Каждого Стр Из Таб Цикл
Стр.UID = Строка(Стр.Док.УникальныйИдентификатор());
КонецЦикла;
КонецПроцедуры
При таком подходе цикл внутри контекста 1С выполняется за доли секунды на десятках тысяч записей, после чего готовая таблица с уже заполненными строковыми значениями передается дальше.
В таблицах СУБД (например, MS SQL Server) поле ссылки _IDRRef хранится в виде binary(16). Порядок байтов в представлении 1С отличается от стандарта RFC 4122. Чтобы получить строковый GUID напрямую на стороне SQL без участия COM и платформы 1С, выполним преобразование порядка байтов с помощью скалярных функций и SUBSTRING.
Для сопоставления имен таблиц и полей метаданным 1С используем метод платформы ПолучитьСтруктуруХраненияБазыДанных(), после чего строим запрос к SQL-серверу:
SELECT
LOWER(
SUBSTRING(sys.fn_varbintohexstr(_IDRRef), 27, 8) + '-' +
SUBSTRING(sys.fn_varbintohexstr(_IDRRef), 23, 4) + '-' +
SUBSTRING(sys.fn_varbintohexstr(_IDRRef), 19, 4) + '-' +
SUBSTRING(sys.fn_varbintohexstr(_IDRRef), 3, 4) + '-' +
SUBSTRING(sys.fn_varbintohexstr(_IDRRef), 7, 12)
) AS GuidString,
_Number AS DocNumber
FROM _Document123
Такой подход позволяет объединить чтение и запись в одну быструю операцию INSERT INTO ... SELECT напрямую между базами на уровне СУБД.
Если необходимо обработать шестнадцатеричное представление или бинарный буфер средствами платформы 1С (начиная с 8.3.10), можно использовать объект БуферДвоичныхДанных. Разберем по шагам алгоритм сдвига и маскирования байтов:
ПБ = ПорядокБайтов.BigEndian;
УИДБуфер = ПолучитьБуферДвоичныхДанныхИзHexСтроки(ГексСтрингУИД);
УИДБуфер.ПорядокБайтов = ПБ;
СтаршиеБиты = УИДБуфер.Прочитать(0, 8);
МладшиеБиты = УИДБуфер.Прочитать(8, 8);
Маска5 = Новый БуферДвоичныхДанных(8, ПБ);
Маска5.ЗаписатьЦелое64(0, 4294967295, ПБ);
Группа5 = МладшиеБиты.Скопировать();
Группа5.ЗаписатьПобитовоеИ(0, Маска5);
СдвинутыйБуфер5 = Новый БуферДвоичныхДанных(16, ПБ);
СдвинутыйБуфер5.Записать(4, Группа5);
СдвинутыйБуфер5 = СдвинутыйБуфер5.Прочитать(8, 8);
Маска4 = Новый БуферДвоичныхДанных(8, ПБ);
Маска4.ЗаписатьЦелое64(0, ЧислоИзШестнадцатеричнойСтроки("0xFFFF00000000"), ПБ);
Группа4 = МладшиеБиты.Скопировать();
Группа4.ЗаписатьПобитовоеИ(0, Маска4);
СдвинутыйБуфер4 = Новый БуферДвоичныхДанных(16, ПБ);
СдвинутыйБуфер4.Записать(10, Группа4);
СдвинутыйБуфер4 = СдвинутыйБуфер4.Прочитать(8, 8);
Маска3 = Новый БуферДвоичныхДанных(8, ПБ);
Маска3.ЗаписатьЦелое64(0, ЧислоИзШестнадцатеричнойСтроки("0xFFFF000000000000"), ПБ);
Группа3 = МладшиеБиты.Скопировать();
Группа3.ЗаписатьПобитовоеИ(0, Маска3);
СдвинутыйБуфер3 = Новый БуферДвоичныхДанных(16, ПБ);
СдвинутыйБуфер3.Записать(14, Группа3);
СдвинутыйБуфер3 = СдвинутыйБуфер3.Прочитать(8, 8);
НоваяСтаршаяГруппа = Новый БуферДвоичныхДанных(8, ПБ);
НоваяСтаршаяГруппа.ЗаписатьПобитовоеИли(0, СдвинутыйБуфер3);
НоваяСтаршаяГруппа.ЗаписатьПобитовоеИли(0, СдвинутыйБуфер4);
НоваяСтаршаяГруппа.ЗаписатьПобитовоеИли(0, СдвинутыйБуфер5);
ПолныйБуфер = Новый БуферДвоичныхДанных(16, ПБ);
ПолныйБуфер.Записать(0, НоваяСтаршаяГруппа);
ПолныйБуфер.Записать(8, СтаршиеБиты);
ПравильныйУИД = НРег(
ПолучитьHexСтрокуИзБуфераДвоичныхДанных(ПолныйБуфер.Прочитать(0, 4)) + "-" +
ПолучитьHexСтрокуИзБуфераДвоичныхДанных(ПолныйБуфер.Прочитать(4, 2)) + "-" +
ПолучитьHexСтрокуИзБуфераДвоичныхДанных(ПолныйБуфер.Прочитать(6, 2)) + "-" +
ПолучитьHexСтрокуИзБуфераДвоичныхДанных(ПолныйБуфер.Прочитать(8, 2)) + "-" +
ПолучитьHexСтрокуИзБуфераДвоичныхДанных(ПолныйБуфер.Прочитать(10, 6)));
Если данные передаются между системами в виде файлов или текстовых потоков, откажемся от сложного разбора XML в пользу ЗаписьJSON и СериализаторXDTO.ЗаписатьJSON(). В отличие от XML, потоковый JSON обрабатывается быстрее, не создает перегрузки оперативной памяти и позволяет выгружать массивы любого размера без необходимости разбивать их на мелкие порции по 1 000 строк.
Начиная с версии 8.3.5, в платформе 1С присутствует встроенный REST-интерфейс OData. При его включении отпадает необходимость вручную преобразовывать ссылки: все сущности возвращаются в формате JSON, где ключевые ссылочные реквизиты уже представлены в виде стандартных строковых GUID (поле Ref_Key).
INSERT. Группируйте строки в конструкции вида INSERT INTO Table (Col1, Col2) VALUES (...), (...), (...) порциями по 500–1000 строк внутри одной транзакции.BULK INSERT на стороне SQL-сервера, что обеспечивает скорость импорта до сотен тысяч записей в секунду.