Как устранить конфликт блокировок и превышение времени ожидания при проведении документов в 1С?

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

При параллельной работе пользователей в клиент-серверном варианте 1С:Предприятия на базе MS SQL Server часто возникает ошибка: «Конфликт блокировок при выполнении транзакции: Microsoft OLE DB Provider for SQL Server: Превышено время ожидания запроса на блокировку (native=1222)». При повторной попытке проведения документ нередко проводится успешно. Разберем детально, почему возникает эта проблема, почему простое увеличение таймаута ожидания не решает ситуацию в корне, и как правильно устранить конфликты блокировок на уровне архитектуры и кода.

Причины возникновения конфликтов блокировок в автоматическом режиме

Проанализируем механику работы 1С в автоматическом режиме управления блокировками данных:

  1. Жесткий уровень изоляции транзакций в СУБД: В автоматическом режиме платформа принудительно переводит транзакции MS SQL Server на уровень изоляции SERIALIZABLE. В этом режиме СУБД накладывает S-блокировки (разделяемые) на читаемые данные и диапазоны ключей (Key-Range locks). Это означает, что чтение данных одним процессом полностью блокирует запись для других параллельных процессов, даже если они работают с разными документами, но обращаются к схожим диапазонам регистров или таблиц.
  2. Эскалация блокировок (Lock Escalation): Когда количество захваченных блокировок строк или страниц одной таблицы превышает системный порог MS SQL Server (обычно около 5000 блокировок), СУБД выполняет эскалацию — заменяет множество мелких блокировок на одну монопольную блокировку всей таблицы (TAB). В этот момент любое проведение других документов, обращающихся к той же таблице, встает в очередь ожидания.
  3. Неоптимальные запросы и сканирование таблиц (Table/Index Scan): Если для запроса внутри транзакции СУБД не может использовать подходящий индекс (из-за устаревшей статистики или отсутствия индексации), выполняется полное чтение таблицы, при котором блокируется вся таблица целиком.
  4. Конкуренция за таблицы итогов регистров: При одновременном списании остатков по популярным позициям номенклатуры или с одного склада разные транзакции пытаются обновить одни и те же строки в таблицах агрегатов и итогов регистров накопления.
  5. Длительные транзакции: Выполнение тяжелых расчетов, запросов к несвязанным данным, обращений к внешним веб-сервисам или файловой системе непосредственно внутри процедуры ОбработкаПроведения удерживает блокировки в СУБД недопустимо долго.

Почему увеличение времени ожидания в конфигураторе не помогает?

Параметр «Время ожидания блокировки данных» в параметрах информационной базы определяет, сколько секунд транзакция будет ждать освобождения ресурса перед аварийным завершением по таймауту. Если мы увеличиваем это значение, ошибка действительно начинает появляться реже, но взамен пользователи получают постоянные зависания интерфейса: транзакции встают в долгие очереди, система начинает работать медленнее, а вероятность взаимных блокировок (Deadlock) многократно возрастает. Поэтому увеличение времени ожидания — это лишь временная мера, маскирующая истинную проблему.

Решение 1. Перевод конфигурации на управляемый режим блокировок

Наиболее эффективный способ устранения эскалаций и блокировок чтения — переход на управляемый режим блокировок данных. В этом режиме на уровне MS SQL Server включается версионирование строк (уровень изоляции READ_COMMITTED_SNAPSHOT), при котором операции чтения не блокируют операции записи, а логические блокировки контролируются самим сервером 1С:

  1. В свойствах конфигурации установим режим управления блокировкой данных в значение «Управляемый» (или «Автоматический и управляемый» для поэтапного перевода).
  2. Для проблемного документа и движимых им регистров установим режим управления блокировкой в значение «Управляемый».
  3. В модуле документа перед чтением остатков программно наложим управляемую блокировку только на списываемые позиции номенклатуры и склад с помощью объекта БлокировкаДанных.

Рассмотрим пример установки управляемой блокировки в коде проведения:


Блокировка = Новый БлокировкаДанных;

ЭлементБлокировки = Блокировка.Добавить("РегистрНакопления.ТоварыНаСкладах");
ЭлементБлокировки.Режим = РежимБлокировкиДанных.Исключительный;
ЭлементБлокировки.ИсточникДанных = ТаблицаТоваров;
ЭлементБлокировки.ИспользоватьИзИсточникаДанных("Номенклатура", "Номенклатура");
ЭлементБлокировки.УстановитьЗначение("Склад", Склад);

Блокировка.Заблокировать();

Решение 2. Включение разделения итогов в регистрах

Если блокировки вызваны конкуренцией за записи остатков по регистрам накопления или бухгалтерии, включим разделение итогов. Для этого в свойствах регистров накопления установим свойство «Использовать разделение итогов» в значение «Истина». На уровне базы данных это создает дополнительные системные разделители для записей итогов, что позволяет нескольким параллельным транзакциям одновременно изменять остатки по одним и тем же аналитикам без ожидания друг друга.

Решение 3. Оптимизация кода проведения документов

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

  1. Вынос подготовительных действий: Все предварительные проверки заполнения, формирование вспомогательных структур, получение курсов валют и чтение нормативно-справочной информации выполним до начала явной или неявной транзакции записи.
  2. Единообразный порядок захвата ресурсов: Проверим, чтобы все документы в конфигурации обращались к таблицам и регистрам в строго одинаковой последовательности. Если Документ 1 пишет сначала в Регистр 1, а затем в Регистр 2, то Документ 2 не должен писать сначала в Регистр 2, а затем в Регистр 1 — это предотвратит взаимоблокировки.
  3. Отказ от тяжелых операций в транзакции: Исключим из обработчиков ПередЗаписью, ПриЗаписи и ОбработкаПроведения отправку почты, вызовы длительных внешних сервисов и работу с диском.
  4. Оперативный контроль остатков: Выполним запись движений с признаком активности, после чего сделаем один точечный запрос на проверку отрицательных остатков, вместо предварительного чтения всех остатков по широким критериям.

Решение 4. Регламентное обслуживание MS SQL Server

Нередко блокировки диапазонов возникают из-за устаревшей статистики СУБД, приводящей к выбору неоптимального плана выполнения запроса. Для поддержания корректной работы СУБД настроим регламентные задачи обслуживания базы данных:

  1. Обновление статистик: Настроим регулярный пересчет статистик с помощью процедуры sp_updatestats или целевого обновления UPDATE STATISTICS WITH FULLSCAN для наиболее активных таблиц регистров.
  2. Реиндексация и дефрагментация: Обеспечим еженедельное перестроение индексов (Rebuild Index) для устранения фрагментации и ускорения поиска по индексам (Index Seek).

Решение 5. Диагностика узких мест с помощью Технологического журнала

Чтобы точно определить, какой именно процесс или строка кода вызывает блокировку, настроим сбор событий в Технологическом журнале 1С. Для этого настроим сбор событий TLOCKS, TTIMEOUT и TDEADLOCK с выводом свойств p:processName, WaitConnections, Context и Sql. Это позволит увидеть точный контекст кода 1С, время ожидания и текст SQL-запроса, удерживающего блокировку.

← На главную