Как устранить конфликты блокировок и взаимоблокировки (deadlocks) на SQL Server в 1С

Системный администратор 1С v8.3 (Обычные формы) 1С:Розница Управленческий учет Торговля и дистрибуция
← На главную

Проблемы с производительностью в крупных торговых сетях часто проявляются внезапно: система, которая работала стабильно месяцами, начинает выдавать ошибки о превышении времени ожидания или, что еще хуже, сообщения о взаимоблокировках (deadlocks). Разберем по шагам, как диагностировать эти конфликты и какие меры необходимо предпринять на уровне СУБД и программного кода 1С.

Отличие ожидания на блокировке от взаимоблокировки (Deadlock)

Для начала проанализируем саму суть проблемы. Ожидание блокировки — это ситуация, когда Транзакция №1 захватила ресурс, а Транзакция №2 ждет его освобождения. Если первая транзакция выполняется слишком долго, у второй истекает время ожидания (TTIMEOUT).

Взаимоблокировка (Deadlock) — это «мертвый узел». Процесс А блокирует Таблицу 1 и пытается достучаться до Таблицы 2. В это же время Процесс Б уже заблокировал Таблицу 2 и ждет доступа к Таблице 1. Они никогда не освободят ресурсы сами. В этом случае SQL Server выбирает «жертву» (deadlock victim) и принудительно прерывает одну из транзакций, чтобы дать возможность работать другой. Именно это часто наблюдается в модулях партионного учета.

Шаг 1: Оперативная диагностика и мониторинг

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

  1. Консоль кластера серверов 1С: Позволяет увидеть текущие сеансы. Обратим внимание на колонку «Блокирует сеанс». Если вы видите длинную цепочку, где один сеанс держит десятки других, это явный признак затянувшейся транзакции.
  2. Монитор активности (Activity Monitor) в SQL Server Management Studio: Помогает определить Session ID, который является инициатором блокировки, и увидеть текст конкретного SQL-запроса.
  3. Использование DBCC OPENTRAN: Выполним команду в консоли SQL, чтобы найти самую старую активную транзакцию. Если время её начала (start time) более 3–5 минут назад, это повод для беспокойства. Для принудительного завершения зависшего процесса используем KILL [ID процесса].

Шаг 2: Регламентное обслуживание SQL Server

Выясним причину, почему SQL Server может выбирать неоптимальные планы запросов, что приводит к избыточным блокировкам. Одной из главных причин является неактуальная статистика. Проанализируем настройки обслуживания:

Обновление статистики: SQL-сервер строит план выполнения запроса на основе данных о распределении значений в таблицах. Если статистика устарела, сервер может вместо поиска по индексу (Index Seek) выбрать полное сканирование таблицы (Index Scan), блокируя при этом тысячи лишних строк.

Очистка процедурного кэша: Иногда в кэше застревает «плохой» план запроса. Чтобы заставить сервер пересчитать планы, используем команду:

DBCC FREEPROCCACHE;

Важно помнить, что эти действия — лишь временная мера. Если код написан неоптимально, дедлоки вернутся.

Шаг 3: Тонкая настройка параметров SQL Server для 1С

Проанализируем критически важные настройки СУБД, которые часто игнорируются:

  1. MAXDOP (Maximum Degree of Parallelism): Для баз 1С крайне рекомендуется установить значение 1. Это запрещает распараллеливание одного запроса. Параллелизм в 1С часто приводит к «внутризапросным» взаимоблокировкам.
  2. Read Committed Snapshot Isolation (RCSI): Если ваша конфигурация использует Управляемые блокировки, убедимся, что на уровне SQL базы включен режим READ_COMMITTED_SNAPSHOT. Это позволит читающим запросам не блокироваться пишущими, что кардинально снижает количество конфликтов.

Шаг 4: Анализ программного кода и порядка захвата ресурсов

Рассмотрим ситуацию с точки зрения разработки. Взаимоблокировки почти всегда возникают из-за разного порядка обращения к таблицам в разных частях кода. Разберем пример:

Чтобы этого избежать, необходимо соблюдать единый порядок захвата ресурсов во всей конфигурации. В типовых решениях 1С принят алфавитный порядок или порядок, определенный методологией фирмы 1С.

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


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

Если в модуле партионного учета (например, УправлениеЗапасамиПартионныйУчет) отсутствуют такие конструкции при включенных управляемых блокировках, это неизбежно приведет к хаосу в транзакциях SQL.

Шаг 5: Технологический журнал как финальный инструмент

Если вышеописанные методы не помогли, настроим Технологический Журнал (ТЖ) для сбора событий TDEADLOCK. Это единственный надежный способ увидеть полную картину на стороне сервера 1С. В файле logcfg.xml добавим сбор событий:


<event query="true">
    <eq property="Name" value="TDEADLOCK"/>
</event>
<event query="true">
    <eq property="Name" value="TTIMEOUT"/>
</event>

Проанализировав логи ТЖ, мы получим точные метаданные объектов 1С и строки кода, которые участвовали в конфликте. Это позволит точечно исправить алгоритмы проведения документов.

Резюме: План действий

  1. Настроить ежедневное обновление статистики SQL и очистку процедурного кэша.
  2. Проверить параметры MAXDOP=1 и включить RCSI для режима управляемых блокировок.
  3. Проверить код на предмет явного вызова БлокировкаДанных перед записью в регистры.
  4. Обеспечить единообразный порядок обращения к таблицам в транзакциях.

Выполнение этих шагов позволит минимизировать конфликты даже в условиях высокой нагрузки торговой сети.

← На главную