При оптимизации параллельной работы пользователей и анализе производительности в Центре управления производительностью (ЦУП) разработчики нередко сталкиваются с ситуацией: в конфигурации включен Управляемый режим блокировок данных, однако при выполнении простого запроса на чтение данных внутри транзакции проведения документа система накладывает исключительную X-блокировку (Exclusive Lock) на уровне СУБД. Особое недоумение вызывает наличие в тексте запроса устаревшей конструкции ДЛЯ ИЗМЕНЕНИЯ, которая, по стандартам разработки платформы 1С, должна полностью игнорироваться в управляемом режиме.
Разберем детально, как платформа 1С:Предприятие 8 работает с блокировками, почему ЦУП и технологический журнал могут фиксировать наложение монопольных блокировок на строках выполнения запросов и как правильно организовать работу с транзакционными блокировками в современных решениях.
Для понимания истоков проблемы проанализируем различия между автоматическим и управляемым режимами блокировок платформы «1С:Предприятие»:
Serializable или Repeatable Read. Конструкция ДЛЯ ИЗМЕНЕНИЯ в конце текста запроса указывает платформе на необходимость трансляции в СУБД специальных подсказок (хинтов) блокировки: например, WITH (UPDLOCK) для Microsoft SQL Server или FOR UPDATE для PostgreSQL и Oracle. Это защищает прочитанные строки от изменения другими транзакциями до момента фактической записи новых данных.Read Committed или механизм версионирования строк Snapshot Isolation / RCSI). В управляемом режиме конструкция ДЛЯ ИЗМЕНЕНИЯ в запросах является устаревшей и должна игнорироваться транслятором платформы, так как чтение данных в СУБД не должно накладывать длительных разделяемых или монопольных блокировок.Если в управляемом режиме конструкция ДЛЯ ИЗМЕНЕНИЯ игнорируется, почему мониторинг показывает появление исключительной блокировки именно на строке Если НЕ Запрос.Выполнить().Пустой() Тогда? Рассмотрим основные технические причины такого поведения СУБД и средств мониторинга.
1. Ожидание блокировки вместо факта её наложения (Lock Wait vs Lock Holder)
Инструменты анализа производительности (ЦУП, технологический журнал по событию TLOCK) связывают инцидент с контекстом, в котором поток перешел в состояние ожидания. Если запрос пытается прочитать данные из таблицы, к которой параллельная транзакция уже применила монопольную блокировку X, текущий сеанс приостанавливает выполнение до снятия чужой блокировки. В отчете ЦУП это выглядит так, будто сам запрос на строке Запрос.Выполнить() пытается наложить или удерживает X-блокировку, хотя на самом деле он ожидает освобождения ресурса.
2. Эскалация блокировок (Lock Escalation) внутри активной транзакции
Запрос выполняется внутри транзакции проведения документа ТекОбъект.Записать(РежимЗаписиДокумента.Проведение). Если до момента вызова проверки транзакция уже успела модифицировать данные (записать движения по другим регистрам, зарегистрировать изменения для планов обмена или обновить объект), эти строки уже удерживаются СУБД с X-блокировкой. При выполнении запроса чтения, если план выполнения оказывается неоптимальным (например, происходит сканирование таблицы Table Scan или неселективный Index Scan), СУБД может принять решение объединить множество мелких строчных блокировок в блокировку страниц или всей таблицы целиком. В результате процесс чтения инициирует эскалацию уже существующих в транзакции исключительных блокировок.
3. Смешанный режим блокировок у объектов конфигурации
Даже если в свойствах конфигурации режим управления блокировками данных установлен в значение Управляемый, в конфигурациях с длительной историей развития (таких как УПП 1.3) у отдельных объектов метаданных (документов, регистров сведений или регистров накопления) свойство Режим управления блокировкой данных может оставаться в значении Автоматический или Автоматический и управляемый. При обращении к таким таблицам платформа применяет правила автоматического режима и продолжает генерировать хинты СУБД.
4. Блокировки во временных таблицах (tempdb)
Если запрос содержит менеджер временных таблиц, конструкции создания временных таблиц или выполняется неявная материализация данных для проверки прав доступа (RLS), СУБД создает объекты в системной базе tempdb. Создание и наполнение страниц временных таблиц всегда сопровождается кратковременными монопольными блокировками системных структур, что также регистрируется монитором блокировок.
5. Особенности версий платформы
В некоторых релизах платформы (в частности, в ветке 8.3.10) имели место внутренние особенности синтаксического транслятора, когда при определенных условиях в сложных запросах к регистрам ключевое слово ДЛЯ ИЗМЕНЕНИЯ ошибочно не отсекалось, приводя к трансляции хинтов UPDLOCK на уровень SQL-сервера даже в управляемом режиме базы данных.
Для полного устранения избыточных блокировок и предотвращения взаимных блокировок (Deadlocks) разберем по шагам правильную последовательность действий.
Поскольку в управляемом режиме данная конструкция не несет полезной нагрузки и может провоцировать некорректное поведение платформы, её необходимо удалить из всех запросов конфигурации. Проанализируем пример оптимизации кода проверки существующих записей.
Исходный фрагмент запроса:
Запрос = Новый Запрос;
Запрос.Текст =
"ВЫБРАТЬ
| Взаиморасчеты.Период КАК Период,
| Взаиморасчеты.Регистратор КАК Регистратор
|ИЗ
| РегистрНакопления.ВзаиморасчетыСКонтрагентами КАК Взаиморасчеты
|ГДЕ
| Взаиморасчеты.ДоговорКонтрагента = &Договор
| И Взаиморасчеты.Период МЕНЬШЕ &ДатаЗапрета
|ДЛЯ ИЗМЕНЕНИЯ"; // Избыточная конструкция!
Исправленный вариант запроса:
Запрос = Новый Запрос;
Запрос.Текст =
"ВЫБРАТЬ ПЕРВЫЕ 1
| 1 КАК ПолеОтбора
|ИЗ
| РегистрНакопления.ВзаиморасчетыСКонтрагентами КАК Взаиморасчеты
|ГДЕ
| Взаиморасчеты.ДоговорКонтрагента = &Договор
| И Взаиморасчеты.Период МЕНЬШЕ &ДатаЗапрета";
Запрос.УстановитьПараметр("Договор", СтруктураПараметров.Договор);
Запрос.УстановитьПараметр("ДатаЗапрета", СтруктураПараметров.ДатаЗапрета);
Если НЕ Запрос.Выполнить().Пустой() Тогда
Отказ = Истина;
// Обработка ошибки доступа по периоду
КонецЕсли;
В управляемом режиме для защиты данных от параллельного изменения другими сеансами используется объект БлокировкаДанных. Управляемая блокировка устанавливается исключительно в пределах открытой транзакции до выполнения чтения или проверки данных.
Посмотрим на типовой пример наложения исключительной управляемой блокировки:
Блокировка = Новый БлокировкаДанных;
ЭлементБлокировки = Блокировка.Добавить("РегистрНакопления.ВзаиморасчетыСКонтрагентами");
ЭлементБлокировки.Режим = РежимБлокировкиДанных.Исключительный;
// Установка условий по измерениям регистра
ЭлементБлокировки.УстановитьЗначение("ДоговорКонтрагента", СтруктураПараметров.Договор);
ЭлементБлокировки.ИсточникДанных = ТаблицаДоговоров; // Можно передавать источник данных
ЭлементБлокировки.ИспользоватьИзИсточникаДанных("ДоговорКонтрагента", "ДоговорКонтрагента");
// Наложение блокировки в менеджере блокировок 1С
Блокировка.Заблокировать();
// После этого выполняем запрос на чтение или контроль остатков
Выборка = Запрос.Выполнить().Выбрать();
Если в процессе проведения документа осуществляется чтение и последующая запись движений по регистру накопления или сведений, наиболее эффективным механизмом является автоматическая блокировка набора записей перед чтением существующих движений.
Рассмотрим применение свойства БлокироватьДляИзменения:
Движения.ВзаиморасчетыСКонтрагентами.БлокироватьДляИзменения = Истина;
Движения.ВзаиморасчетыСКонтрагентами.Записывать = Истина;
// При вызове метода Записать() или чтении набора движений
// платформа автоматически наложит управляемую блокировку по регистратору
Движения.ВзаиморасчетыСКонтрагентами.Записать();
Для того чтобы запросы на чтение данных не конфликтовали с операциями модификации на уровне базы данных, необходимо удостовериться в корректности настроек параметров СУБД:
READ_COMMITTED_SNAPSHOT (RCSI). Это позволяет операторам SELECT читать снимок данных без наложения разделяемых (S) блокировок и ожидания завершения транзакций модификации (X-блокировок).Режим управления блокировкой данных у всех объектов метаданных, участвующих в проведении, и переведем их в режим Управляемый.Соблюдение этих правил гарантирует отсутствие избыточных ожиданий на блокировках и обеспечивает максимальную параллельность при проведении документов в высоконагруженных информационных базах 1С.