При интеграции 1С с внешними базами данных через механизм Внешние источники данных (ВИД) разработчики часто сталкиваются с необъяснимой задержкой. Ситуация выглядит следующим образом: одна база (например, узел РИБ) записывает данные в таблицу MS SQL, но другая база видит эти изменения не сразу, а лишь спустя 5–10 секунд. При этом, если проверить таблицу напрямую через SQL Server Management Studio (SSMS), данные появляются там мгновенно.
В этой статье мы подробно разберем, почему возникает этот эффект «протухшего кэша», и рассмотрим несколько способов обеспечения оперативного получения данных в реальном времени.
Прежде чем переходить к коду, давайте проанализируем ситуацию. Платформа 1С спроектирована таким образом, чтобы минимизировать нагрузку на сеть и сервер базы данных. Когда выполняется запрос к ВнешнемуИсточникуДанных, 1С считывает данные и помещает их в локальный кэш сеанса. При повторном обращении к той же таблице в течение короткого промежутка времени платформа может вернуть данные из кэша, не обращаясь к реальному SQL-серверу.
Именно поэтому в консоли SQL Management Studio мы видим актуальную картину (она работает напрямую), а в коде 1С — старую. Платформа «не знает», что внешняя таблица была изменена другим сеансом или сторонним приложением.
Наиболее простым и эффективным программным методом решения проблемы является использование транзакций 1С. Рассмотрим, как это работает. При вызове метода НачатьТранзакцию() для внешнего источника, платформа переходит в режим гарантированной согласованности данных. Чтобы обеспечить эту согласованность внутри транзакции, 1С принудительно сбрасывает локальный кэш и выполняет чтение непосредственно из SQL-сервера.
Разберем пример кода, который позволяет получить актуальные данные без задержки:
// Указываем имя нашего внешнего источника данных
ВнешнийИсточник = ВнешниеИсточникиДанных.ИмяВашегоСервераSQL;
// Открываем транзакцию, чтобы заставить 1С перечитать данные из SQL
ВнешнийИсточник.НачатьТранзакцию();
Попытка
// Выполняем запрос или чтение таблицы
Запрос = Новый Запрос;
Запрос.Текст =
"ВЫБРАТЬ
| ВнешняяТаблица.Поле1,
| ВнешняяТаблица.Поле2
|ИЗ
| ВнешнийИсточникДанных.ИмяВашегоСервераSQL.Таблица.ИмяТаблицы КАК ВнешняяТаблица";
РезультатЗапроса = Запрос.Выполнить();
// Обработка данных...
// Завершаем транзакцию
ВнешнийИсточник.ЗафиксироватьТранзакцию();
Исключение
// В случае ошибки обязательно откатываем транзакцию
ВнешнийИсточник.ОтменитьТранзакцию();
ЗаписьЖурналаРегистрации("Ошибка чтения SQL", УровеньЖурналаРегистрации.Ошибка,,, ОписаниеОшибки());
КонецПопытки;
Важный нюанс: даже если вы только читаете данные, вызов ЗафиксироватьТранзакцию() необходим для корректного закрытия сессии обмена.
Иногда проблема кроется в настройках самого MS SQL Server. По умолчанию в SQL используется уровень изоляции READ COMMITTED. Это означает, что читающий процесс может ожидать завершения пишущего процесса. В высоконагруженных системах это создает дополнительные задержки.
Проанализируем настройку Read Committed Snapshot Isolation (RCSI). Если включить этот режим на уровне базы данных SQL, то читающие сеансы 1С не будут блокироваться пишущими. Они будут всегда видеть последнюю зафиксированную версию данных (snapshot) на момент начала запроса.
Для включения этого режима выполните в SQL Management Studio следующий скрипт:
ALTER DATABASE [ИмяВашейБазы] SET ALLOW_SNAPSHOT_ISOLATION ON;
ALTER DATABASE [ИмяВашейБазы] SET READ_COMMITTED_SNAPSHOT ON WITH ROLLBACK IMMEDIATE;
Это значительно повышает параллельность работы и помогает 1С быстрее получать подтвержденные данные из внешнего источника.
Посмотрим на настройки метаданных. В свойствах таблицы внешнего источника данных в дереве конфигурации есть параметр «Блокировка данных».
Если специфика вашей задачи требует гарантированного отсутствия кэширования (например, мониторинг датчиков или критически важных статусов в реальном времени), рассмотрим альтернативу встроенному механизму ВИД. Это использование объекта COMОбъект("ADODB.Connection").
Этот метод работает в обход механизмов платформы 1С и обращается к драйверу SQL напрямую. Здесь кэширование 1С полностью отсутствует. Выясним, как реализовать такое подключение:
Connection = Новый COMОбъект("ADODB.Connection");
ConnectionString = "Driver={SQL Server};Server=ИмяСервера;Database=ИмяБазы;Uid=Логин;Pwd=Пароль;";
Попытка
Connection.Open(ConnectionString);
Command = Новый COMОбъект("ADODB.Command");
Command.ActiveConnection = Connection;
Command.CommandText = "SELECT Top 1 Status FROM MonitoringTable WHERE ID = 1";
RecordSet = Command.Execute();
Пока НЕ RecordSet.EOF Цикл
ТекущийСтатус = RecordSet.Fields("Status").Value;
RecordSet.MoveNext();
КонецЦикла;
Connection.Close();
Исключение
Сообщить("Ошибка прямого доступа к SQL: " + ОписаниеОшибки());
КонецПопытки;
Метод через ADO является самым «быстрым», но он менее удобен, так как требует ручного формирования строк подключения и не позволяет использовать привычный язык запросов 1С.
Проанализируем настройки драйвера на сервере 1С. Внешние источники данных работают через ODBC-провайдер. В настройках ODBC Data Source Administrator обратите внимание на параметры Pooling (Пул соединений).
Если пул настроен на слишком длительное удержание соединений, может возникнуть ситуация, когда сеанс 1С использует «старое» соединение с устаревшими параметрами сессии SQL. В некоторых случаях помогает принудительное переподключение источника через метод:
ВнешниеИсточникиДанных.ИмяИсточника.УстановитьОбщиеПараметрыСоединения(Параметры)
Это инициирует создание нового физического соединения с сервером, что гарантированно очищает все уровни кэширования.
Подводя итог, если вы столкнулись с задержкой в 5–10 секунд при работе с внешним SQL в 1С, наиболее правильным путем будет:
Применяя эти методы, мы обеспечиваем высокую скорость обмена данными и исключаем ошибки, связанные с получением неактуальной информации в распределенных системах.