При интеграции систем часто возникает задача соединить данные из информационной базы 1С (например, справочник или регистр сведений) с таблицей из внешнего источника данных (ВИД). На первый взгляд кажется логичным написать классический запрос с оператором ЛЕВОЕ СОЕДИНЕНИЕ, полагаясь на наличие индексов. Однако при попытке выполнить такой запрос платформа выдает исключение: «Получение данных из нескольких источников данных недопустимо!».
Разберем архитектурные причины этого поведения платформы, выясним, как работают временные таблицы во внешних источниках, и рассмотрим проверенные способы решения поставленной задачи.
Проанализируем архитектуру механизма запросов платформы «1С:Предприятие». Когда мы выполняем запрос к базе данных, платформа не выполняет соединения таблиц собственными силами в оперативной памяти сервера приложений. Вместо этого встроенный транслятор преобразует текст запроса 1С в нативный диалект SQL той СУБД, на которой развернута информационная база (MS SQL Server, PostgreSQL, Oracle и т.д.), и отправляет его на исполнение целиком на сторону сервера баз данных.
В платформе 1С отсутствует распределенный (федеративный) SQL-движок. Каждый объект Запрос строго привязан к одному контексту: либо к рабочей информационной базе, либо к конкретному внешнему источнику данных. СУБД информационной базы 1С ничего не знает о таблицах сторонней базы, и наоборот. По этой причине прямое объединение или соединение таблиц из разных источников внутри одного текста запроса синтаксически заблокировано разработчиками платформы.
Иногда возникает идея обойти ограничение через создание временных таблиц: поместить данные из ВИД во временную таблицу и затем связать ее с таблицей 1С. Рассмотрим, как на самом деле работает этот механизм начиная с версии платформы 8.3:
ПОМЕСТИТЬ ВнешнийИсточникДанных.<ИмяИсточника>.ВременнаяТаблица.<ИмяТаблицы>.tempdb для MS SQL Server). Следовательно, соединить ее с таблицами основной базы 1С все равно невозможно, так как они физически размещены в разных базах или даже на разных серверах.Самым простым и штатным способом объединить данные двух баз на уровне платформы является Система компоновки данных. СКД умеет работать с несколькими источниками и выполняет соединение наборов данных силами собственного процессора компоновки.
Разберем по шагам правильную настройку схемы компоновки данных:
ГДЕ Ключ В (&МассивКлючей).МассивКлючей второго набора.Важный нюанс производительности: если не настроить передачу параметра в связях наборов, СКД выполнит запрос ко второму набору без фильтрации. В этом случае во временную память сервера 1С будет выгружена вся внешняя таблица целиком. Настройка передачи массива ключей заставляет платформу считывать данные из внешнего источника небольшими порциями, задействуя индекс по ключевому полю на стороне внешней СУБД.
Если результат требуется получить программно в модуле, стандартным подходом является разделение задачи на два последовательных запроса с промежуточной передачей данных через объект ТаблицаЗначений.
Посмотрим на пример реализации данного алгоритма:
// Шаг 1. Получаем необходимые данные из внешнего источника данных
ЗапросВИД = Новый Запрос;
ЗапросВИД.Текст =
"ВЫБРАТЬ
| ВнешняяТаблица.КодТовара КАК КодТовара,
| ВнешняяТаблица.ОстатокНаСкладе КАК ОстатокНаСкладе
|ИЗ
| ВнешнийИсточникДанных.ВнешняяБаза.Таблица.Остатки КАК ВнешняяТаблица
|ГДЕ
| ВнешняяТаблица.Актуален = ИСТИНА";
ТЗ_ВнешниеДанные = ЗапросВИД.Выполнить().Выгрузить();
// Шаг 2. Передаем полученную таблицу в запрос к базе 1С
Запрос1С = Новый Запрос;
Запрос1С.Текст =
"ВЫБРАТЬ
| ТЗ.КодТовара КАК КодТовара,
| ТЗ.ОстатокНаСкладе КАК ОстатокНаСкладе
|ПОМЕСТИТЬ ВТ_ВнешниеДанные
|ИЗ
| &ТЗДанные КАК ТЗ
|ИНДЕКСИРОВАТЬ ПО
| КодТовара
|;
|
|////////////////////////////////////////////////////////////////////////////////
|ВЫБРАТЬ
| Номенклатура.Ссылка КАК Номенклатура,
| Номенклатура.Артикул КАК Артикул,
| ЕСТЬNULL(ВТ_ВнешниеДанные.ОстатокНаСкладе, 0) КАК ВнешнийОстаток
|ИЗ
| Справочник.Номенклатура КАК Номенклатура
| ЛЕВОЕ СОЕДИНЕНИЕ ВТ_ВнешниеДанные КАК ВТ_ВнешниеДанные
| ПО Номенклатура.Артикул = ВТ_ВнешниеДанные.КодТовара
|ГДЕ
| НЕ Номенклатура.ЭтоГруппа";
Запрос1С.УстановитьПараметр("ТЗДанные", ТЗ_ВнешниеДанные);
Результат = Запрос1С.Выполнить().Выгрузить();
Обратите внимание на директиву ИНДЕКСИРОВАТЬ ПО при помещении таблицы значений во временную таблицу. Это гарантирует быстрое соединение с основной таблицей базы 1С.
Стоит учитывать, что обратная операция невозможна: передать ТаблицуЗначений платформы 1С в качестве параметра во внешний источник данных нельзя, так как сторонние СУБД не поддерживают внутреннюю сериализацию коллекций значений 1С.
Когда объемы соединяемых данных достигают сотен тысяч или миллионов строк, перегонять их через оперативную память сервера «1С:Предприятия» становится неэффективно. В таких сценариях интеграцию переносят на уровень СУБД:
VIEW), которое нативно объединяет внешние таблицы и таблицы базы 1С с использованием физических индексов обеих сторон.В этом случае платформа 1С выполняет обычный запрос к одному источнику, а всю тяжелую работу по оптимизации и соединению выполняет внешний сервер СУБД.