Почему зависает ВыборкаИзменений.Получить при обмене данными и как это исправить

Программист 1С v8.3 (Управляемые формы) IT и автоматизация бизнеса
← На главную

При настройке регулярного обмена данными между информационными базами 1С через планы обмена разработчики нередко сталкиваются с ситуацией, когда процесс выгрузки в интерактивном режиме выполняется без замечаний, но намертво зависает при запуске в фоновом или регламентном задании. При этом в журнале регистрации и протоколе обмена нет никаких сообщений об ошибках, а выполнение останавливается на попытке чтения очередного объекта.

Разберем детально, почему возникает подобное зависание, как локализовать проблемный объект метаданных и какими способами можно гарантированно обойти эту проблему.

Анализ механизма работы выборки изменений

Рассмотрим типовой фрагмент программного кода, который часто применяется в обработках выгрузки данных:


ВыборкаИзменений = ПланыОбмена.ВыбратьИзменения(ЗаписьСообщения.Получатель, ЗаписьСообщения.НомерСообщения, МассивВыгружаемыхМетаданных);

Пока ВыборкаИзменений.Следующий() Цикл
    ЗаписатьВПротоколВыполнения("Метка 1");
    Данные = ВыборкаИзменений.Получить();
    ЗаписатьВПротоколВыполнения("Метка 2");
    // Дальнейшая обработка и сериализация объекта
КонецЦикла;

Метод ВыборкаИзменений.Получить() возвращает объект данных целиком из информационной базы (например, ДокументОбъект со всеми его табличными частями). В фоновом сеансе регламентного задания этот вызов может приводить к бесконечному ожиданию по следующим причинам:

  1. Эскалация и пересечение блокировок в СУБД: Метод ПланыОбмена.ВыбратьИзменения() монопольно фиксирует номера сообщений в таблицах регистрации изменений. При последующем вызове Получить() платформа считывает данные из основных таблиц документа и его табличных частей. Если в ночное время параллельно выполняются другие регламентные задачи (индексация, пересчет итогов, фоновое проведение), возникает перекрестная блокировка (Deadlock или Lock Escalation) между таблицами изменений и физическими таблицами СУБД.
  2. Особенности работы неинтерактивного сеанса и RLS: При объектном чтении система накладывает механизмы проверки прав доступа на уровне записей. В неинтерактивном контексте построитель запросов СУБД может выбрать неоптимальный план выполнения с полным сканированием таблиц.
  3. Кэширование структуры метаданных: Рабочий процесс сервера rphost может блокировать поток при попытке десериализации тяжелого объекта в память.

Локализация проблемного метаданного

Для выявления конкретного типа данных, на котором останавливается выполнение, разобьем выгрузку на отдельные итерации по метаданным. Выясним, какой именно документ или справочник вызывает зависание:

  1. Ограничим массив метаданных, передаваемый в ПланыОбмена.ВыбратьИзменения(), обрабатывая каждый объект метаданных по отдельности.
  2. Используем стандартную обработку регистрации изменений, чтобы проанализировать зарегистрированные ссылки.
  3. Проверим регистрацию тестового единичного документа каждого проблемного типа.

Решение 1: Замена объектной выборки на прямой запрос к таблице изменений

Наиболее надежный и производительный способ решения проблемы — полный отказ от метода ВыборкаИзменений.Получить() в пользу выборки ссылок прямым запросом к виртуальной таблице изменений. Рассмотрим реализацию данного подхода по шагам:


Запрос = Новый Запрос;
Запрос.Текст = 
    "ВЫБРАТЬ
    |	Изм.Ссылка КАК Ссылка
    |ИЗ
    |	Документ.ПриходнаяНакладная.Изменения КАК Изм
    |ГДЕ
    |	Изм.Узел = &УзелОбмена";

Запрос.УстановитьПараметр("УзелОбмена", ЗаписьСообщения.Получатель);

РезультатЗапроса = Запрос.Выполнить();
Выборка = РезультатЗапроса.Выбрать();

МассивСсылок = Новый Массив;

Пока Выборка.Следующий() Цикл
    // Выгружаем данные по ссылке или сериализуем объект
    ВыгрузитьПоПравилам(Выборка.Ссылка);
    МассивСсылок.Добавить(Выборка.Ссылка);
КонецЦикла;

// После успешной выгрузки очищаем регистрацию изменений
Если МассивСсылок.Количество() > 0 Тогда
    ПланыОбмена.УдалитьРегистрациюИзменений(ЗаписьСообщения.Получатель, МассивСсылок);
КонецЕсли;

Такой подход исключает неявные монопольные блокировки всей таблицы регистрации, не требует загрузки полных объектов в память без необходимости и стабильно отрабатывает в любых фоновых заданиях.

Решение 2: Порционная выборка изменений (батчинг)

Если требуется сохранить стандартный механизм выгрузки по правилам обмена через объект ЗаписьСообщения, применим порционную выборку. Метод ПланыОбмена.ВыбратьИзменения() позволяет передавать массив конкретных ссылок третьим параметром:


// Считываем порцию ссылок (например, по 200 штук)
Запрос = Новый Запрос;
Запрос.Текст = 
    "ВЫБРАТЬ ПЕРВЫЕ 200
    |	Изм.Ссылка КАК Ссылка
    |ИЗ
    |	Документ.ПриходнаяНакладная.Изменения КАК Изм
    |ГДЕ
    |	Изм.Узел = &УзелОбмена
    |	И Изм.НомерСообщения ЕСТЬ NULL";

Запрос.УстановитьПараметр("УзелОбмена", ЗаписьСообщения.Получатель);
МассивСсылок = Запрос.Выполнить().Выгрузить().ВыгрузитьКолонку("Ссылка");

Если МассивСсылок.Количество() > 0 Тогда
    ВыборкаИзменений = ПланыОбмена.ВыбратьИзменения(ЗаписьСообщения.Получатель, ЗаписьСообщения.НомерСообщения, МассивСсылок);
    
    Пока ВыборкаИзменений.Следующий() Цикл
        Данные = ВыборкаИзменений.Получить();
        // Сериализация и запись в сообщение
    КонецЦикла;
КонецЕсли;

Обработка данных небольшими порциями предотвращает эскалацию блокировок таблиц на стороне СУБД и снижает нагрузку на оперативную память рабочего процесса сервера 1С.

Рекомендации по администрированию СУБД и расписанию

Чтобы минимизировать риски зависания фоновых обменов, выполним следующие профилактические шаги:

  1. Разнесение по времени: Проверим расписание фоновых заданий и исключим пересечение ночного обмена данными с реиндексацией таблиц, обновлением прав доступа и пересчетом итогов.
  2. Обслуживание индексов: Настроим регулярное обновление статистики и дефрагментацию индексов для служебных таблиц изменений (таблицы с суффиксом _ChngR в базе данных SQL).
  3. Очистка кэша: При нетипичном поведении конкретных метаданных выполним очистку серверного кэша сеансов и перезапуск рабочих процессов кластера rphost.
← На главную