Чёрный пояс 1С. Управляемые блокировки при списании остатков: код, который не деградирует под нагрузкой
Реализация товаров и услуг, регистр ТоварыНаСкладах, конец рабочего дня — и вместо мирного проведения документов в очереди звучит знакомое: «Конфликт блокировок при выполнении транзакции». Проблема не в железе. Проблема в том, что чтение остатков перед списанием честно блокирует таблицу целиком там, где могло бы блокировать только нужные строки.
Легенда практического занятия
В распределённой ERP-системе холдинга при одновременной записи движений документов РеализацияТоваровУслуг по регистру накопления ТоварыНаСкладах регулярно возникают конфликты взаимных блокировок СУБД. Нужно перевести контур на управляемые блокировки, написать корректный BSL-код и спроектировать индексную стратегию, которая не убьёт скорость записи.
Задание
- Объясните физическую разницу уровней изоляции транзакций на СУБД в автоматическом и управляемом режимах платформы.
- Напишите фрагмент BSL, накладывающий исключительную блокировку на списываемые остатки и разделяемую блокировку на регистр резервов.
- Спроектируйте индексную стратегию: объясните физический смысл разделения итогов и ограничения СУБД Oracle по размеру ключа индекса.
1. Что физически отличается в СУБД
В автоматическом режиме блокировок платформа опирается на тяжёлые уровни изоляции СУБД — Repeatable Read или Serializable — и они блокируют таблицы целиком, а не отдельные строки. В управляемом режиме платформа переходит на лёгкий Read Committed (для MS SQL Server — его снимок-вариант, Read Committed Snapshot), а точечную блокировку конкретных строк берёт на себя объект БлокировкаДанных уровня приложения. Именно поэтому переход на управляемый режим без переписывания кода проведения ничего не даёт — вы снимаете тяжёлую блокировку СУБД, но если не поставить свою точечную, документы снова начнут конфликтовать, просто на другом уровне.
2. Эталонный код блокировки
// Создание объекта управляемой блокировки
Блокировка = Новый БлокировкаДанных;
// Наложение исключительной блокировки на ТоварыНаСкладах (списываемые позиции)
ЭлементТоварыНаСкладах = Блокировка.Добавить("РегистрНакопления.ТоварыНаСкладах");
ЭлементТоварыНаСкладах.Режим = РежимБлокировкиДанных.Исключительный;
ЭлементТоварыНаСкладах.ИсточникДанных = ЭтотОбъект.Товары; // Табличная часть документа
ЭлементТоварыНаСкладах.ИспользоватьИзИсточникаДанных("Номенклатура", "Номенклатура");
ЭлементТоварыНаСкладах.ИспользоватьИзИсточникаДанных("Склад", "Склад");
// Наложение разделяемой блокировки на ТоварыВРезервеНаСкладах (только чтение резервов)
ЭлементРезервы = Блокировка.Добавить("РегистрНакопления.ТоварыВРезервеНаСкладах");
ЭлементРезервы.Режим = РежимБлокировкиДанных.Разделяемый;
ЭлементРезервы.ИсточникДанных = ЭтотОбъект.Товары;
ЭлементРезервы.ИспользоватьИзИсточникаДанных("Номенклатура", "Номенклатура");
ЭлементРезервы.ИспользоватьИзИсточникаДанных("Склад", "Склад");
// Вызов наложения блокировки перед выполнением запроса остатков
Блокировка.Заблокировать();
3. Индексы и разделение итогов
Флаг Разрешить разделение итогов заставляет платформу писать дельты движений отдельными новыми строками итоговых таблиц вместо обновления одной общей записи. Это резко снижает конкуренцию на запись, но увеличивает объём таблиц итогов — цену платите чтением: остаток нужно собрать суммированием группы строк, пока они не свёрнуты регламентным пересчётом.
С дополнительными некластерными индексами логика обратная: каждый лишний индекс ускоряет выборку, но замедляет COMMIT, потому что СУБД обязана обновить все связанные индексы при каждой записи. На регистрах с высокой частотой проведения документов это прямой компромисс между скоростью отчётов и скоростью ввода.
V81C_INDEX_BIG. Забытое об этом требование — частая причина падений реструктуризации на боевых базах Oracle с многомерными регистрами.Что проверить у себя на проекте
- Не осталось ли в коде проведения смеси автоматических и управляемых блокировок — режим должен быть переключён последовательно на всей цепочке документов, иначе выигрыш исчезает.
- Соответствует ли режим блокировки (исключительный/разделяемый) реальной операции — списание требует исключительной, проверка резервов часто обходится разделяемой.
- Есть ли план по своевременному пересчёту итогов при включённом разделении — без него объём таблиц итогов растёт бесконтрольно.
Создать токен →