Ситуация, когда при проведении документа в одном сеансе блокируется работа других пользователей, является классической проблемой для баз данных, работающих в автоматическом режиме управления блокировками. Особенно остро это проявляется в конфигурациях на базе MS SQL Server. Разберем подробно, почему это происходит и как обеспечить параллельную работу пользователей без «зависаний».
Проанализируем механизм работы 1С в автоматическом режиме. При использовании этого режима платформа устанавливает уровень изоляции транзакций SERIALIZABLE на стороне SQL Server. Это самый жесткий уровень изоляции, необходимый для обеспечения полной целостности данных. Его главная особенность — использование блокировок диапазонов (Range Locks).
Рассмотрим, как это работает на практике. Когда первый сеанс начинает проведение документа (например, Чек ККМ), он накладывает блокировки на записи в регистрах. В режиме SERIALIZABLE SQL Server блокирует не только конкретную строку с товаром, но и весь диапазон значений индекса вокруг этой строки. Если второй сеанс пытается продать тот же товар или даже другой товар, который попадает в «заблокированный диапазон», транзакция второго сеанса приостанавливается и ожидает завершения первой.
В ходе диагностики с помощью системных процедур sp_lock и sp_who2 часто можно увидеть конструкцию WITH(SERIALIZABLE) в SQL-запросах. Это прямое указание СУБД на использование блокирующего режима, который предотвращает появление так называемых «фантомных записей».
Проанализируем еще одну причину — эскалацию блокировок. Если транзакция изменяет большое количество строк (обычно более 5000 в одной таблице), SQL Server может решить, что управлять множеством мелких блокировок слишком накладно. В этом случае он заменяет их одной исключительной блокировкой всей таблицы (Table Lock). В этот момент работа всех остальных пользователей с данной таблицей полностью прекращается.
Также важно обратить внимание на индексы. Если запрос внутри транзакции (например, по регистру ЦеныАТТ) не может эффективно использовать существующие индексы, SQL Server вынужден выполнять сканирование всей таблицы (Table Scan). В режиме SERIALIZABLE это автоматически приводит к блокировке всей таблицы до момента фиксации транзакции.
Это стратегически верный и наиболее эффективный способ решения проблемы. Разберем по шагам, что дает переход на управляемые блокировки:
READ COMMITTED (или READ COMMITTED SNAPSHOT), который не блокирует читающие транзакции пишущими.БлокировкаДанных.Для реализации этого метода необходимо в свойствах конфигурации (или конкретных объектов) установить режим управления блокировками в значение Управляемый и в коде процедуры ОбработкаПроведения явно прописать установку блокировок:
Блокировка = Новый БлокировкаДанных;
ЭлементБлокировки = Блокировка.Добавить("РегистрНакопления.ТоварыНаСкладах");
ЭлементБлокировки.УстановитьЗначение("Склад", Склад);
ЭлементБлокировки.Режим = РежимБлокировкиДанных.Исключительный;
Блокировка.Заблокировать();
Если переход на управляемые блокировки требует слишком больших трудозатрат, можно попробовать оптимизировать работу СУБД. Включение механизма Snapshot Isolation на уровне MS SQL Server позволяет читающим запросам получать данные из версии строк в tempdb, не ожидая завершения транзакций записи.
Однако помните: в автоматическом режиме 1С все равно будет форсировать уровень SERIALIZABLE для многих операций записи, поэтому эффект от RCSI может быть ограниченным. Этот метод лучше всего работает в паре с переходом на управляемый режим.
Рассмотрим дополнительные методы повышения параллельности:
Разделение итогов. Это позволит разным транзакциям одновременно прибавлять значения к остаткам, используя специальные технологические таблицы, что снижает вероятность конфликтов на уровне одной записи.ЦеныАТТ или ОстаткиТоваров) созданы индексы, соответствующие набору измерений в ваших запросах. Это позволит СУБД накладывать точечные блокировки, а не блокировать диапазоны.Записать() и концом процедуры проведения, тем меньше шансов поймать блокировку.Если вы столкнулись с «зависанием», воспользуйтесь следующей методикой:
SPID (идентификатор процесса) заблокированного сеанса в 1С.sp_who2, чтобы увидеть, какой процесс блокирует ваш SPID.DBCC INPUTBUFFER(НомерПроцесса), чтобы увидеть последний запрос, вызвавший проблему.Index Spool или Table Scan при уровне изоляции SERIALIZABLE — это явный признак необходимости оптимизации индексов или перехода на управляемый режим.Посмотрим на пример типичного запроса, который может вызвать блокировку в автоматическом режиме (из-за отсутствия NOLOCK в транзакции):
SELECT TOP 21
_Document236_R._Date_Time AS _A1,
_Document236_R._Number AS _A2,
_Document236_R._IDRRef AS _A11RRef
FROM _Document236 _Document236_R WITH(SERIALIZABLE)
WHERE _Document236_R._Date_Time = @P2
ORDER BY _Document236_R._Date_Time
Именно наличие WITH(SERIALIZABLE) в таких запросах, генерируемых платформой, является корнем проблем с производительностью в многопользовательской среде.