При интеграции 1С со сторонними базами данных разработчики нередко сталкиваются с ситуацией: один и тот же запрос к таблице внешнего источника данных (ВИД) в интерактивной консоли запросов отрабатывает за доли секунды, а при выполнении из встроенного языка через метод Запрос.Выполнить() «зависает» на десятки секунд. Разберем подробнее, почему возникает такая разница в производительности и как правильно оптимизировать запросы к внешним источникам.
Проанализируем механизм взаимодействия платформы 1С с внешней СУБД (MS SQL Server, PostgreSQL, Oracle, MySQL) через драйвер ODBC:
УстановитьПараметр(), тип значения в 1С может незначительно отличаться от типа поля во внешней таблице (например, строка неограниченной длины вместо фиксированного VARCHAR(N), либо тип NVARCHAR вместо VARCHAR). В результате внешняя СУБД вынуждена на лету конвертировать тип каждого значения в таблице, из-за чего перестают работать индексы (происходит полный просмотр таблицы Table Scan / Index Scan вместо точечного поиска Index Seek).SET ANSI_NULLS, QUOTED_IDENTIFIER), что заставляет внешнюю базу компилировать изолированные планы запросов.Разберем основной способ решения проблемы на уровне текста запроса 1С. Чтобы внешняя СУБД гарантированно использовала индекс, необходимо явно ограничить тип и длину передаваемого параметра с помощью функции ВЫРАЗИТЬ.
Посмотрим на пример текста запроса до оптимизации:
Запрос = Новый Запрос;
Запрос.Текст =
"ВЫБРАТЬ
| ВнешняяТаблица.Идентификатор КАК Идентификатор,
| ВнешняяТаблица.Наименование КАК Наименование
|ИЗ
| ВнешнийИсточникДанных.ВнешняяБД.Таблица.Контрагенты КАК ВнешняяТаблица
|ГДЕ
| ВнешняяТаблица.Код = &КодКлиента";
Запрос.УстановитьПараметр("КодКлиента", СокрЛП(ПараметрКод));
Результат = Запрос.Выполнить();
Если поле Код во внешней базе имеет тип VARCHAR(20), неявная передача строки без явного ограничения типа приводит к сканированию всей таблицы. Исправим запрос, применив явное приведение типов:
Запрос = Новый Запрос;
Запрос.Текст =
"ВЫБРАТЬ
| ВнешняяТаблица.Идентификатор КАК Идентификатор,
| ВнешняяТаблица.Наименование КАК Наименование
|ИЗ
| ВнешнийИсточникДанных.ВнешняяБД.Таблица.Контрагенты КАК ВнешняяТаблица
|ГДЕ
| ВнешняяТаблица.Код = ВЫРАЗИТЬ(&КодКлиента КАК Строка(20))";
Запрос.УстановитьПараметр("КодКлиента", СокрЛП(ПараметрКод));
Результат = Запрос.Выполнить();
Важно: Всегда проверяйте, чтобы тип в конструкции ВЫРАЗИТЬ в точности соответствовал типу и длине колонки в целевой СУБД.
Проанализируем настройки конфигурации в ветке «Внешние источники данных»:
NULL, идентичные структуре таблицы во внешней базе.Если проблема вызвана устаревшей статистикой распределения данных во внешней базе, СУБД может генерировать некорректный план при компиляции запроса:
UPDATE STATISTICS для MS SQL Server или ANALYZE для PostgreSQL).OPTION (RECOMPILE) или OPTIMIZE FOR UNKNOWN для соответствующего параметризованного запроса.Рассмотрим альтернативные варианты взаимодействия, если прямой запрос к таблицам ВИД по-прежнему вызывает задержки:
WITH (NOLOCK)), можно воспользоваться объектом COMОбъект("ADODB.Connection").