При выполнении обмена данными между современными конфигурациями (например, 1С:Управление торговлей 11) и базами на платформе 1С:Предприятие 7.7 под управлением MS SQL Server нередко возникает ситуация, когда процесс загрузки внезапно останавливается. В окне состояния отображается обработка определенного числа объектов, процесс загружает процессор, а у активных пользователей в этот момент появляются критические ошибки вида SQL State: HYT00 Native: 0 Message: [Microsoft][ODBC SQL Server Driver]Timeout expired. При этом запись и проведение документов блокируются по всей базе.
Разберем детально, почему возникает подобное поведение платформы, как локализовать узкое место и как правильно настроить поиск и запись объектов при пакетном обмене данными.
Выясним причину, которая чаще всего приводит к «мертвому» зависанию базы при выполнении выгрузки или загрузки. Основная проблема кроется в алгоритмах сопоставления загружаемых объектов с существующими документами в базе 1С 7.7.
Рассмотрим, как работает поиск в 1С 7.7 на уровне СУБД:
_1SJOURN. Такой поиск выполняется практически мгновенно методом точечной выборки по индексу.ДатаСоздания, НомерСоздания или строковый идентификатор) без включения отбора, стандартный метод НайтиПоРеквизиту() не может использовать индекс._1SJOURN и соответствующих таблиц шапок документов DH<ID> вплоть до самой первой записи в базе (например, за 10–12 лет работы).При объеме базы в сотни тысяч или миллионы документов такое сканирование накладывает разделяемые блокировки (Shared Locks) на диапазоны строк. При интенсивном параллельном чтении происходит эскалация блокировок до уровня всей таблицы, из-за чего все остальные пользователи при попытке выполнить методы Записать() или Провести() получают ошибку таймаута ожидания блокировки Timeout expired.
Чтобы исключить сканирование всей таблицы журнала при загрузке новых документов, необходимо правильно организовать структуру реквизитов и процедуру поиска в конфигураторе 1С 7.7.
Разберем по шагам правильную настройку:
ИД_Обмена или НомерСоздания), обязательно установим флаг «Отбор по реквизиту» (или «Сортировка»). Это заставит СУБД создать отдельный индекс по полю соответствующей таблицы.
Док = СоздатьОбъект("Документ.РасходнаяНакладная");
Если Док.НайтиПоРеквизиту("ИД_Обмена", ЗначениеИдентификатора, 1) = 1 Тогда
// Документ найден по индексу, обновляем реквизиты
Док.Записать();
Иначе
// Документ не найден, создаем новый объект без сканирования истории
Док.Новый();
Док.ИД_Обмена = ЗначениеИдентификатора;
Док.Записать();
КонецЕсли;
Проанализируем распространенную ошибку, когда весь файл обмена (сотни или тысячи документов) загружается внутри одной общей транзакции либо вообще без явного управления транзакциями. При проведении документов формируются движения по регистрам и проводкам, что удерживает монопольные блокировки таблиц итогов.
Для предотвращения взаимных блокировок применим порционную фиксацию данных с механизмом повторных попыток при возникновении конфликтов:
КоличествоВТранзакции = 0;
НачатьТранзакцию();
Пока ЧтениеXML.Прочитать() Цикл
// Код чтения и заполнения объекта
Попытка
ОбъектДокумент.Записать();
Если ФлагПроведения = 1 Тогда
ОбъектДокумент.Провести();
КонецЕсли;
Исключение
ОтменитьТранзакцию();
ЗаписьЖурналаРегистрации("Ошибка записи документа: " + ОписаниеОшибки(),
"ОбменXML", "Загрузка", 3);
// Запуск следующей транзакции для продолжения обработки
НачатьТранзакцию();
КоличествоВТранзакции = 0;
Продолжить;
КонецПопытки;
КоличествоВТранзакции = КоличествоВТранзакции + 1;
// Фиксируем данные порциями по 50 документов
Если КоличествоВТранзакции >= 50 Тогда
ЗафиксироватьТранзакцию();
НачатьТранзакцию();
КоличествоВТранзакции = 0;
КонецЕсли;
КонецЦикла;
Если КоличествоВТранзакции > 0 Тогда
ЗафиксироватьТранзакцию();
КонецЕсли;
Если оптимизация кода выполнена, но СУБД продолжает выбирать неоптимальные планы выполнения запросов (например, сканирование кластерного индекса вместо поиска по некластерному индексу), необходимо проверить состояние базы на стороне SQL Server.
_1SJOURN, таблиц шапок документов DH* и таблиц проводок/регистров.Simple), чтобы файл журнала транзакций не разрастался бесконтрольно и не создавал дополнительную нагрузку на дисковую подсистему.