При активной многопользовательской работе в конфигурации «Управление производственным предприятием» (УПП) администраторы и разработчики часто сталкиваются со следующей ошибкой СУБД:
Транзакция (идентификатор процесса 53) вызвала взаимоблокировку ресурсов блокировка с другим процессом и стала жертвой взаимоблокировки. Запустите транзакцию повторно. HRESULT=80004005, SQLSrvr: SQLSTATE=40001
Эта ошибка означает, что на уровне СУБД произошел критический конфликт блокировок — Deadlock (взаимоблокировка). В данной статье мы подробно разберем, почему возникает эта ошибка при вызове общего модуля ПолныеПрава, рассмотрим внутренние механизмы платформы и СУБД, а также изучим эффективные методы устранения этой проблемы как на уровне кода 1С, так и на уровне настроек MS SQL Server.
Для начала проанализируем место возникновения ошибки. Сбой происходит в процедуре ЗаписатьНаборЗаписейНаСервере общего модуля ПолныеПрава на строке 1283:
Процедура ЗаписатьНаборЗаписейНаСервере(ИмяРегистра, Регистратор, ТаблицаДвижений = Неопределено, ТипРегистра = "РегистрНакопления") Экспорт
Если ТипРегистра = "РегистрНакопления" Тогда
Набор = РегистрыНакопления[ИмяРегистра].СоздатьНаборЗаписей();
Если ТаблицаДвижений <> Неопределено Тогда
Набор.мТаблицаДвижений = ТаблицаДвижений;
ОбщегоНазначения.ВыполнитьДвижениеПоРегистру(Набор);
КонецЕсли;
ИначеЕсли ТипРегистра = "РегистрБухгалтерии" Тогда
Набор = РегистрыБухгалтерии[ИмяРегистра].СоздатьНаборЗаписей();
ИначеЕсли ТипРегистра = "РегистрСведений" Тогда
Набор = РегистрыСведений[ИмяРегистра].СоздатьНаборЗаписей();
ИначеЕсли ТипРегистра = "РегистрРасчета" Тогда
Набор = РегистрыРасчета[ИмяРегистра].СоздатьНаборЗаписей();
КонецЕсли;
Если ТаблицаДвижений <> Неопределено Тогда
Набор.Загрузить(ТаблицаДвижений);
КонецЕсли;
Набор.Отбор.Регистратор.Установить(Регистратор);
Набор.Записать(); // Строка 1283
КонецПроцедуры
Эта процедура является универсальным механизмом УПП для записи движений документов под полными правами (чтобы обойти ограничения прав доступа текущего пользователя). Ошибка возникает непосредственно при выполнении метода Набор.Записать().
Когда один или несколько пользователей одновременно проводят однотипные или разные документы, затрагивающие одни и те же регистры, транзакции начинают конкурировать за физические таблицы базы данных СУБД. Если СУБД обнаруживает, что транзакция А ждет освобождения ресурса, заблокированного транзакцией Б, а транзакция Б в свою очередь пытается заблокировать ресурс, удерживаемый транзакцией А, СУБД принудительно прерывает одну из них (делает «жертвой взаимоблокировки»), чтобы предотвратить бесконечное зависание.
Рассмотрим подробнее физические причины возникновения дедлоков в среде 1С:Предприятие и MS SQL Server:
Serializable или Repeatable Read.Нет, перезапуск СУБД или службы сервера 1С не решит проблему. Это действие является временным решением, которое лишь принудительно разорвет текущие «зависшие» транзакции и очистит кэш. Как только пользователи возобновят активную работу в базе данных, взаимоблокировки вернутся. Проблему необходимо решать системно на уровне кода конфигурации и настроек СУБД.
Выясним причину дедлока с помощью диагностических инструментов. Нам необходимо понять, какие именно транзакции, документы и таблицы СУБД вошли в клинч.
Для сбора подробной информации о блокировках настроим сбор событий в технологическом журнале на сервере 1С. Создадим или отредактируем файл logcfg.xml (обычно он располагается в каталоге C:\Program Files\1cv8\conf\):
<?xml version="1.0" encoding="UTF-8"?>
<config xmlns="http://v8.1c.ru/v8/config">
<log location="C:\v8logs\deadlocks" history="24">
<event>
<eq property="Name" value="TDEADLOCK"/>
</event>
<event>
<eq property="Name" value="TTIMEOUT"/>
</event>
<property name="all"/>
</log>
</config>
Событие TDEADLOCK зафиксирует факт взаимоблокировки на уровне СУБД, а свойство DeadlockConnectionIntersections покажет номера конфликтующих сеансов 1С и имена заблокированных таблиц СУБД (например, _AccumRg12345 — физическая таблица регистра накопления).
Для точного анализа графа взаимоблокировки (Deadlock Graph) настроим сессию Extended Events в MS SQL Server Management Studio (SSMS):
xml_deadlock_report.При возникновении ошибки SQL Server сформирует наглядный XML-граф, где будет видно, какой именно SQL-запрос от имени первого процесса заблокировал ресурс, и какой запрос от второго процесса привел к дедлоку.
Рассмотрим подробнее практические шаги по устранению взаимоблокировок, разделенные на два уровня: настройки СУБД и оптимизацию конфигурации 1С.
Если конфигурация УПП находится на полной поддержке и вы не можете вносить изменения в код, примените следующие административные меры:
1. Включение режима RCSI (Read Committed Snapshot Isolation)
Это самый мощный инструмент для борьбы с дедлоками в базах данных, работающих в автоматическом режиме блокировок. Включение версионирования строк позволяет операциям чтения не блокировать операции записи (и наоборот). Читающие транзакции будут получать данные из временного хранилища tempdb без наложения разделяемых (Shared) блокировок на основные таблицы.
Чтобы включить данный режим, выполните в SSMS следующий скрипт (предварительно переведя базу в монопольный режим):
USE master;
ALTER DATABASE [ИмяВашейБазы] SET SINGLE_USER WITH ROLLBACK IMMEDIATE;
ALTER DATABASE [ИмяВашейБазы] SET READ_COMMITTED_SNAPSHOT ON;
ALTER DATABASE [ИмяВашейБазы] SET MULTI_USER;
2. Регулярное обновление статистики и обслуживание индексов
Настройте ежедневные регламентные задания на SQL-сервере. Неоптимальные планы запросов — частая причина блокировок. Рекомендуется использовать ежедневную дефрагментацию и реиндексацию таблиц регистра накопления, а также обновление статистики с флагом FULLSCAN:
UPDATE STATISTICS [ИмяВашейБазы].[dbo].[_AccumRg12345] WITH FULLSCAN;
3. Ограничение параллелизма (параметр MAXDOP)
В настройках SQL Server установите параметр Max Degree of Parallelism (MAXDOP) в значение 1 (или в соответствии с официальными рекомендациями фирмы 1С для вашего многоядерного процессора). Параллельные планы тяжелых запросов внутри транзакций часто приводят к локальным взаимоблокировкам потоков внутри самой СУБД.
Если у вас есть возможность доработки конфигурации, примените следующие архитектурные подходы:
1. Перевод регистров на управляемый режим блокировок
Наиболее надежный и правильный путь в платформе 1С:Предприятие 8.3 — перевести конфигурацию (или конкретные проблемные регистры) на Управляемый режим блокировок.
В управляемом режиме СУБД работает с уровнем изоляции Read Committed, а контроль транзакционной целостности переносится на уровень сервера приложений 1С.
Блокировки накладываются точечно по измерениям регистров с помощью объекта БлокировкаДанных. Разберем пример программной блокировки остатков перед записью набора:
Блокировка = Новый БлокировкаДанных;
ЭлементБлокировки = Блокировка.Добавить("РегистрНакопления.Продажи");
ЭлементБлокировки.Режим = РежимБлокировкиДанных.Исключительный;
ЭлементБлокировки.УстановитьЗначение("Организация", ТекущаяОрганизация);
Блокировка.Заблокировать();
Этот код гарантирует, что транзакция захватит управление только по конкретной Организации, не затрагивая документы по другим юридическим лицам.
2. Выравнивание порядка записи в регистры
Проанализируем все документы, которые пишут данные в конфликтующие регистры. Убедимся, что запись наборов данных всегда происходит в строго одинаковом порядке. Если Документ А пишет сначала в "Продажи", затем в "ОстаткиТоваров", то и Документ Б должен использовать точно такую же последовательность.
3. Оптимизация и вынос последовательностей
Если технологический журнал указывает на частые конфликты в таблицах регистрации последовательностей (например, Партионного учета), рекомендуется:
4. Разделение тяжелых документов
Если пользователи проводят огромные документы (сотни строк спецификаций), блокировка накладывается на длительное время. Разработайте регламент для пользователей по разделению больших документов на несколько мелких, либо оптимизируйте алгоритмы проведения, минимизируя время нахождения транзакции в открытом состоянии (перенесите все тяжелые расчеты до начала транзакции проведения).
Применение комплекса мер по настройке СУБД (включение RCSI, обслуживание индексов) совместно с переводом критических регистров на управляемый режим блокировок гарантированно решит проблему взаимоблокировок в 1С:УПП и значительно повысит общую производительность системы.