При анализе производительности и параллельной работы пользователей в 1С:Предприятии нередко возникает ситуация: в журнале или специализированных сервисах мониторинга зафиксировано длительное ожидание блокировки жертвой, в то время как у виновника отображается минимальное значение длительности (например, доли секунды). В результате возникает ложное впечатление, что виновник мгновенно освободил ресурс, а жертва продолжала ждать до наступления таймаута.
Разберем детально, как устроена механика фиксации блокировок, что на самом деле означает показатель длительности в аналитических инструментах, а также выясним основные причины возникновения конфликтов блокировок и способы их устранения.
Главная причина непонимания ситуации кроется в трактовке колонок отчетов технологического журнала и систем мониторинга:
0,0001 сек, это означает лишь то, что он захватил ресурс практически мгновенно и без конкурентного ожидания. Однако сама исключительная блокировка продолжает удерживаться виновником вплоть до завершения его транзакции (команды ЗафиксироватьТранзакцию() или окончания обработчика проведения).Проанализируем технические факторы, приводящие к блокировкам при проведении документов и выполнении фоновых процедур:
is_read_committed_snapshot_on и snapshot_isolation_state_desc отключены (равны 0 / OFF), MS SQL Server накладывает разделяемые S-блокировки при чтении, провоцируя конфликты страниц и эскалацию блокировок даже при корректной логике кода 1С.УпорядочитьТаблицуПоДокументу, списание по ФИФО или контроль последовательностей при параллельном проведении документов по одним и тем же аналитическим разрезам (организация, склад, номенклатура).Рассмотрим комплекс мер, направленных на оптимизацию параллельной работы и исключение таймаутов.
Переведем рабочую базу данных в режим версионирования строк, чтобы операции чтения не блокировали операции записи на уровне СУБД. Для этого выполним команду в консоли SQL Server Management Studio:
ALTER DATABASE [ИмяБазыДанных] SET READ_COMMITTED_SNAPSHOT ON WITH ROLLBACK IMMEDIATE;
Проверим текущее состояние базы данных с помощью запроса:
SELECT name, is_read_committed_snapshot_on, snapshot_isolation_state_desc
FROM sys.databases
WHERE name = 'ИмяБазыДанных';
Значение is_read_committed_snapshot_on должно стать равным 1.
Для точной локализации виновников настроим технологический журнал платформы на сбор событий блокировок и таймаутов с получением контекста выполнения:
<log location="C:\LOGS\Locks" history="24">
<event>
<eq property="name" value="TLOCKS"/>
</event>
<event>
<eq property="name" value="TTIMEOUT"/>
</event>
<event>
<eq property="name" value="TDEADLOCK"/>
</event>
<property name="all"/>
</log>
Это позволит сопоставить момент начала транзакции виновника, захват ресурса и фактическое время вызова фиксации транзакции.
При использовании явных управляемых блокировок в коде конфигурации всегда устанавливаем фильтры по максимальному числу измерений. Рассмотрим пример корректной установки управляемой блокировки:
Блокировка = Новый БлокировкаДанных;
ЭлементБлокировки = Блокировка.Добавить("РегистрНакопления.ТоварыНаСкладах");
ЭлементБлокировки.Режим = РежимБлокировкиДанных.Исключительный;
ЭлементБлокировки.УстановитьЗначение("Организация", Шапка.Организация);
ЭлементБлокировки.УстановитьЗначение("Склад", Шапка.Склад);
ЭлементБлокировки.ИсточникДанных = ТаблицаТоваров;
ЭлементБлокировки.ИспользоватьИзИсточникаДанных("Номенклатура", "Номенклатура");
Блокировка.Заблокировать();
Соблюдаем ключевые правила при проектировании транзакционной логики: