Ошибки вида «Конфликт блокировок при выполнении транзакции: Превышено максимальное время ожидания» являются одной из самых сложных проблем при эксплуатации высоконагруженных систем на базе 1С. Ситуация осложняется, когда время проведения обычного документа возрастает с 3–5 до 30–40 секунд, что парализует работу бухгалтерии и склада. Особенно часто это встречается в связке 1С:Комплексная автоматизация 1.1 (или УПП 1.3) и СУБД PostgreSQL или MS SQL Server.
В этой статье мы разберем причины возникновения таких задержек, проанализируем программный код, вызывающий сбои, и рассмотрим комплекс мер по оптимизации сервера и конфигурации.
Разберем ситуацию: при проведении платежного поступления или накладной система обращается к общим модулям для записи движений. Ошибка часто локализуется в методе Записать(). Рассмотрим типичный стек ошибки:
{ОбщийМодуль.ПолныеПрава.Модуль(1283)}: Ошибка при вызове метода контекста (Записать)
Проанализируем этот участок кода в типовой конфигурации. Как правило, там находится процедура ЗаписатьНаборЗаписейНаСервере, которая выполняет финальную фиксацию движений в базе данных. Основные «виновники» конфликтов в старых редакциях (КА 1.1, УПП 1.3) — это:
_AccRgAT0). При записи проводок по 62 или 60 счету система пытается монопольно заблокировать итоги. Если одновременно бухгалтер проводит реализацию, а кассир — поступление, возникает очередь (ожидание), которая заканчивается аварией по таймауту.Если вы используете PostgreSQL, стандартных настроек «из коробки» недостаточно для стабильной работы 1С. Рассмотрим параметры, которые необходимо проверить в файле postgresql.conf:
max_locks_per_transaction: Установите значение не менее 256 или 512. 1С генерирует огромное количество мелких блокировок в рамках одной транзакции проведения.autovacuum: Должен быть включен. Однако для таблиц итогов (например, _AccRg) полезно периодически запускать VACUUM FULL вручную в периоды отсутствия пользователей, чтобы физически убрать «мертвые» строки (bloat), которые замедляют поиск данных.shared_buffers (должен быть около 25-30% от ОЗУ) и work_mem критически важны для скорости выполнения запросов при проведении.Рассмотрим процедуру, на которую ругается система. Проанализируем пример оптимизации записи, чтобы избежать лишних блокировок. В некоторых случаях система пытается записать пустой набор записей или повторно перезаписывает уже существующий без изменений.
Посмотрим на пример модификации процедуры ЗаписатьНаборЗаписейНаСервере, которая помогает снизить количество конфликтов на регистре Хозрасчетный:
Процедура ЗаписатьНаборЗаписейНаСервере(ИмяРегистра, Регистратор, ТаблицаДвижений = Неопределено, ТипРегистра = "РегистрНакопления") Экспорт
Если ТипРегистра = "РегистрНакопления" Тогда
Набор = РегистрыНакопления[ИмяРегистра].СоздатьНаборЗаписей;
// ... стандартная логика
ИначеЕсли ТипРегистра = "РегистрБухгалтерии" Тогда
// Оптимизация: если это Хозрасчетный и данных нет, можно пропустить запись в ряде случаев
Если ИмяРегистра = "Хозрасчетный" И ТаблицаДвижений <> Неопределено И ТаблицаДвижений.Количество() = 0 Тогда
Возврат;
КонецЕсли;
Набор = РегистрыБухгалтерии[ИмяРегистра].СоздатьНаборЗаписей;
// ... остальной код
КонецЕсли;
Набор.Отбор.Регистратор.Установить(Регистратор);
Если ТаблицаДвижений <> Неопределено Тогда
Набор.Загрузить(ТаблицаДвижений);
КонецЕсли;
Попытка
Набор.Записать();
Исключение
// Здесь можно добавить логгирование, чтобы понять, какой именно объект вызвал конфликт
ВызватьИсключение;
КонецПопытки;
КонецПроцедуры
Современные версии платформы 8.3 часто автоматически загружают исправления (патчи) от фирмы 1С. Проанализируем ситуацию: иногда расширение с исправлением (например, EF_00_00596270) может содержать ошибку в подписках на события. Если при записи документа срабатывает подписка из расширения, которая делает тяжелый запрос к базе, это блокирует основную транзакцию.
Рекомендация: Если ошибки начались внезапно, проверьте список установленных расширений. Попробуйте временно снять флаг «Активность» с последних установленных патчей и проверьте скорость проведения документов.
Выясним еще одну причину медленной работы: рассчитанность итогов. Если в базе данных итоги рассчитаны по дату, которая сильно отстает от текущей (например, на полгода назад), то при проведении документа «сегодняшним» числом система вынуждена динамически вычислять остатки за весь этот период.
Выполним следующие действия:
_AccRgAT0.Проанализируем код из сообщения 20, где устанавливаются параметры сеанса для границ запрета. Этот код выполняется очень часто и задействует запросы к регистру сведений ГраницыЗапретаИзмененияДанных.
Процедура УстановитьПараметрГраницыЗапретаИзмененияДанных Экспорт
Если РольДоступна("ПолныеПрава") И НЕ Константы.ПрименятьДатуЗапретаДляПолныхПрав.Получить Тогда
ПараметрыСеанса.ГраницыЗапретаИзмененияДанных = Новый ХранилищеЗначения(Неопределено, Новый СжатиеДанных(0));
Возврат;
КонецЕсли;
// ... далее идет тяжелый запрос по организациям и группам пользователей
КонецПроцедуры
Совет: Включите константу «Не применять дату запрета для полных прав». Это позволит администраторам и роботам (если они работают под полными правами) избегать выполнения этих ресурсоемких процедур внутри транзакций записи, что снизит вероятность взаимных блокировок.
Для решения проблемы «Конфликта блокировок» мы рекомендуем действовать пошагово:
max_locks_per_transaction и настроить autovacuum).Помните, что в конфигурациях на обычных формах (КА 1.1) переход на полностью управляемые блокировки — процесс трудоемкий и рискованный, поэтому начинать стоит именно с оптимизации текущей архитектуры и настроек сервера.