При интеграции современных версий 1С (8.x) с унаследованными системами на базе 1С 7.7 программисты часто сталкиваются с критическим падением производительности. Ситуация, когда один и тот же запрос мгновенно отрабатывает внутри "семерки", но выполняется мучительно долго (минутами) при вызове через OLE (COM-соединение), является классической проблемой. В этой статье мы подробно разберем, почему так происходит, и рассмотрим эффективные методики ускорения обмена данными.
Для начала проанализируем физику процесса. Когда мы создаем объект Запрос через OLE-соединение, каждое обращение к его свойствам или методам из 1С 8 вызывает процедуру, называемую маршалингом. Это процесс передачи данных через границы адресных пространств двух разных процессов.
Если ваш запрос в 1С 7.7 возвращает 1000 строк, и вы начинаете обходить их в цикле на стороне 1С 8, обращаясь к Запрос.Код или Запрос.Наименование, система совершает тысячи межпроцессных вызовов. Каждый такой вызов стоит "дорого" с точки зрения ресурсов процессора и времени ожидания. Именно здесь кроется основная задержка, а не в самой выборке данных в базе 7.7.
Вторая важная причина — использование условий "через точку". Рассмотрим ситуацию: когда мы пишем в условии запроса Номенклатура.Код = "123", 1С 7.7 вынуждена для каждой записи регистра или документа выполнять неявное соединение со справочником номенклатуры, что в разы медленнее, чем фильтрация по прямой ссылке (внутреннему идентификатору).
Прежде всего, разберем, как правильно передавать параметры в запрос 7.7. Вместо того чтобы фильтровать по строковому коду или артикулу внутри текста запроса, необходимо заранее найти нужный объект в базе 7.7 и передать его в запрос как объект (ссылку).
Рассмотрим пример правильной подготовки параметров. Вместо формирования строки условия вручную, мы используем объект СписокЗначений базы 7.7, который наполняем ссылками. Это позволяет платформе 7.7 использовать индексы таблиц максимально эффективно.
Посмотрим на пример кода на стороне 1С 8:
// Создаем список значений в контексте 7.7
СписокДляЗапроса = База77.CreateObject("СписокЗначений");
// Ищем объект в 7.7
Товар77 = База77.CreateObject("Справочник.Номенклатура");
Если Товар77.НайтиПоКоду(КодИзВосьмерки) = 1 Тогда
СписокДляЗапроса.ДобавитьЗначение(Товар77.ТекущийЭлемент());
КонецЕсли;
// Теперь в тексте запроса используем этот список
ТекстЗапроса = "
|Номенклатура = Регистр.Остатки.Номенклатура;
|Условие(Номенклатура в СписокДляЗапроса);";
Важный нюанс: Чтобы запрос работал быстро, переменная СписокДляЗапроса должна быть доступна в контексте выполнения запроса. Если вы используете EvalExpr, убедитесь, что объекты не уничтожаются сборщиком мусора до завершения выполнения метода Выполнить().
Это самый эффективный способ при работе через OLE. Мы минимизируем количество обращений к COM-объектам, перенося всю логику "внутрь" 7.7. Вместо того чтобы тянуть объект Запрос в 1С 8, мы заставляем 7.7 выполнить запрос, выгрузить его в ТаблицуЗначений и вернуть нам уже готовый результат.
Разберем по шагам. Сначала в Глобальном модуле базы 1С 7.7 создаем экспортную функцию:
Функция ВыполнитьЗапросДля8(ТекстЗапроса) Экспорт
Запрос = СоздатьОбъект("Запрос");
ТЗ = СоздатьОбъект("ТаблицаЗначений");
Если Запрос.Выполнить(ТекстЗапроса) = 1 Тогда
Запрос.Выгрузить(ТЗ, 0, 0); // Выгружаем без итогов для скорости
Возврат ТЗ;
КонецЕсли;
Возврат 0;
КонецФункции
Теперь на стороне 1С 8 мы вызываем эту функцию один раз. Мы получим один OLE-объект (Таблицу Значений), который содержит все данные. Это гораздо быстрее, чем последовательно перебирать результаты запроса.
Проанализируем пример вызова из 1С 8:
РезультатТЗ = База77.ВыполнитьЗапросДля8(СформированныйТекстЗапроса);
// Далее работаем с РезультатТЗ как с COM-объектом
Для Ном = 1 По РезультатТЗ.КоличествоСтрок() Цикл
ТекЗначение = РезультатТЗ.ПолучитьЗначение(Ном, "Количество");
КонецЦикла;
Совет: Если строк очень много (десятки тысяч), даже обход OLE-таблицы значений может быть медленным. В этом случае используйте функцию ЗначениеВСтрокуВнутр(ТЗ) в 7.7, передавайте полученную гигантскую строку в 1С 8 и там парсите её. Это исключит тысячи обращений к COM-интерфейсу.
Если база 7.7 работает в формате DBF или SQL, и вам нужна максимальная скорость, можно полностью отказаться от OLE-запросов 1С в пользу прямых SQL-запросов. Это позволяет считывать данные напрямую из файлов таблиц (.dbf) или таблиц SQL-сервера, минуя уровень бизнес-логики 1С 7.7.
Рассмотрим пример подключения к DBF-базе через провайдер VFPOLEDB. Этот метод позволяет выполнять SELECT запросы к таблицам 1С 7.7 (например, RG* — остатки регистров, SC* — справочники) практически мгновенно.
ПутьКБазе = "C:\Bases\1c77base\";
Соединение = Новый COMОбъект("ADODB.Connection");
// Используем Visual FoxPro OLE DB Provider
Соединение.ConnectionString = "Provider=VFPOLEDB.1;Data Source=" + ПутьКБазе + ";Collating Sequence=MACHINE";
Соединение.Open();
Command = Новый COMОбъект("ADODB.Command");
Command.ActiveConnection = Соединение;
// Пример запроса к справочнику (sc84) и остаткам регистра (rg405)
Command.CommandText = "SELECT Спр.descr as Name, SUM(Рег.sp411) as Rest
|FROM rg405 Рег
|LEFT JOIN sc84 Спр ON Спр.id = Рег.sp408
|GROUP BY Спр.descr";
RecordSet = Command.Execute();
Пока НЕ RecordSet.EOF Цикл
Сообщить(RecordSet.Fields.Item("Name").Value + ": " + RecordSet.Fields.Item("Rest").Value);
RecordSet.MoveNext();
КонецЦикла;
Этот метод требует знания структуры таблиц (файла 1cv7.dd), но он обеспечивает скорость, недоступную штатным средствам OLE.
Для ускорения взаимодействия между 1С 8 и 7.7 придерживайтесь следующих правил:
Номенклатура.Код). Сначала найдите объект, затем передайте его ссылку в запрос.Соблюдение этих рекомендаций позволяет сократить время выполнения операций с десятков минут до нескольких секунд, обеспечивая комфортную работу пользователей в гетерогенных средах 1С.