Почему управляемая блокировка в 1С работает избыточно и как это исправить

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

При разработке высоконагруженных систем на платформе 1С:Предприятие 8 механизмы управляемых блокировок становятся основным инструментом обеспечения параллельности работы пользователей. Однако часто возникают ситуации, когда, казалось бы, правильно настроенная блокировка по конкретным измерениям (например, по складу и номенклатуре) внезапно начинает «тормозить» другие сеансы, которые работают с совершенно иными данными. Разберем по шагам, почему это происходит и как правильно проектировать код проведения документов.

Анализ проблемы: почему зависают смежные документы

Рассмотрим стандартную ситуацию: программист устанавливает блокировку на регистр накопления РегистрНакопления.ОстаткиТоваровНаскладах. В коде явно указаны отборы по конкретному складу и списку номенклатуры. Ожидается, что другой документ, в котором указан другой склад, должен провестись беспрепятственно. Но на практике второй сеанс замирает на строке Блокировка.Заблокировать().

Проанализируем пример кода, который часто становится причиной такой проблемы:


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

На первый взгляд код корректен. Однако корень проблемы часто кроется не в самой блокировке, а в действиях, которые выполняются до её установки. Выясним причину подробнее.

Влияние старых движений документа

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

Движения.ОстаткиТоваровНаскладах.Записать();

Что происходит в этот момент:

  1. Метод Записать() без параметров очищает старые записи набора.
  2. Платформа 1С автоматически накладывает исключительную блокировку на те комбинации измерений, которые были в удаляемых записях.
  3. Если в старом документе был «Склад А», а в новом мы выбрали «Склад Б», то вызов Записать() заблокирует «Склад А».
  4. Дальнейшая установка управляемой блокировки кодом по «Складу Б» лишь добавляет еще одну область в таблицу блокировок.

В результате, если другой пользователь в это же время пытается работать со «Складом А», он будет ждать завершения транзакции первого пользователя, даже если в текущем (новом) состоянии документа этот склад вообще не упоминается.

Взаимодействие управляемых и объектных блокировок

Важно понимать механику: управляемая блокировка, которую мы пишем кодом, накладывается параллельно с теми блокировками, которые платформа накладывает автоматически при записи наборов записей или самих объектов. Если в конфигурации установлен Управляемый режим блокировок, 1С сама не ставит блокировки СУБД при чтении, но она обязана ставить их при записи данных для обеспечения целостности.

Рассмотрим нюансы:

Как правильно организовать блокировку данных

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

  1. Установка управляемой блокировки в самом начале: Код блокировки должен стоять до любых манипуляций с данными регистра. Если мы планируем изменять или удалять старые движения, блокировка должна охватывать как новые значения измерений, так и старые.
  2. Использование ТЗ для объединения данных: Проанализируем ситуацию, когда склад изменился. Нам нужно заблокировать и старый склад (чтобы его никто не прочитал, пока мы удаляем записи), и новый (чтобы мы могли корректно записать новые остатки).
  3. Минимизация вызовов Записать(): Избегайте явного вызова Движения.Записать() в начале процедуры, если у документа в свойствах стоит «Удаление движений: Удалять автоматически».

Проблема пустых значений и гранулярность

Иногда система блокирует больше данных, чем нужно, из-за «пустых» фильтров. Если в ЭлементБлокировки.УстановитьЗначение() передать Неопределено или пустую ссылку (например, склад не заполнен), менеджер блокировок 1С может интерпретировать это как требование заблокировать весь диапазон по данному измерению. Это мгновенно парализует работу всех пользователей с этим регистром.

Также не стоит забывать про эскалацию блокировок на уровне СУБД (MS SQL, PostgreSQL). Если количество заблокированных строк превышает порог (обычно около 5000–6000), СУБД может принять решение заменить тысячи блокировок строк одной блокировкой всей таблицы. В управляемом режиме 1С это случается реже, но при интенсивной записи больших наборов данных об этом стоит помнить.

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

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

Это позволит точно увидеть: блокируется ли конкретная номенклатура или происходит «захват» всего регистра из-за ошибки в коде или отсутствия индекса по измерениям.

Эффективность индексов

Управляемая блокировка работает эффективно только тогда, когда набор фильтров (Склад, Номенклатура) соответствует ведущим полям индекса. Если вы блокируете данные по «Номенклатуре», но она не является первым или вторым полем в индексе регистра (а первым идет «Склад», который вы не указали в блокировке), система будет вынуждена заблокировать гораздо больший диапазон данных, так как не сможет быстро локализовать нужные записи в индексе.

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

Итоги и рекомендации

Подводя итог, для корректной работы блокировок придерживайтесь следующих правил:

  1. Устанавливайте блокировку до того, как вызываете методы записи или очистки движений.
  2. Если документ перепроводится, блокировка должна учитывать и те данные, которые будут удалены (старые измерения).
  3. Всегда проверяйте заполненность значений, передаваемых в УстановитьЗначение().
  4. Следите за тем, чтобы измерения, по которым ставится блокировка, были проиндексированы.
  5. Используйте разделяемый режим (Разделяемый), если вам нужно только прочитать остатки для контроля, и исключительный (Исключительный), если вы гарантированно будете записывать данные в эту область.

Соблюдение этих принципов позволит значительно повысить параллельность работы системы и избежать необъяснимых «зависаний» при проведении документов.

← На главную