Бөлісу құралы:


Руководство по взаимоблокировкам

Применимо: SQL Server База данных SQL Azure Управляемый экземпляр SQL Azure azure Synapse Analytics Analytics Platform System (PDW)

В этой статье подробно рассматриваются взаимоблокировки в ядро СУБД SQL Server. Взаимоблокировки вызваны конкурирующими параллельными блокировками в базе данных, часто в многофакторных транзакциях. Дополнительные сведения о блокировке транзакций см . в руководстве по блокировке транзакций и настройке версий строк.

Дополнительные сведения об идентификации и предотвращении взаимоблокировок в База данных SQL Azure см. в статье "Анализ и предотвращение взаимоблокировок в База данных SQL Azure".

Общие сведения о взаимоблокировках

Взаимоблокировка возникает, когда две или более задачи постоянно блокируют друг друга из-за того, что задача каждой из сторон блокирует ресурс, который пытаются заблокировать другие задачи. Например:

  • Транзакция А создает общую блокировку строки 1.

  • Транзакция Б создает общую блокировку строки 2.

  • Транзакция А теперь запрашивает монопольную блокировку строки 2 и блокируется до того, как транзакция Б закончится и освободит общую блокировку строки 2.

  • Транзакция Б теперь запрашивает монопольную блокировку строки 1 и блокируется до того, как транзакция А закончится и освободит общую блокировку строки 1.

Транзакция A не может завершиться до завершения транзакции B, но транзакция B блокируется транзакцией A. Это условие также называется циклической зависимостью: транзакция A имеет зависимость от транзакции B, а транзакция B закрывает круг, имея зависимость от транзакции A.

Обе транзакции в взаимоблокировке ожидают вечно, если взаимоблокировка не нарушается внешним процессом. Монитор взаимоблокировки SQL Server ядро СУБД периодически проверяет наличие задач, которые находятся в взаимоблокировке. Если монитор обнаруживает цикличную зависимость, то выбирается одна задача, для которой транзакция будет завершена с ошибкой. Это позволяет другой задаче завершить свою транзакцию. Приложение с транзакцией, завершающейся ошибкой, может повторить транзакцию, которая обычно завершается после завершения другой заблокированной транзакции.

Взаимоблокировки часто путают с обычными блокировками. Если транзакция запрашивает блокировку на ресурс, заблокированный дугой транзакцией, то запрашивающая транзакция ожидает до тех пор, пока блокировка не освобождается. По умолчанию транзакции SQL Server не истекает, если LOCK_TIMEOUT только не задано. Транзакция запроса заблокирована, не заблокирована, так как запрашивающая транзакция не сделала ничего, чтобы заблокировать транзакцию, принадлежающую блокировке. В конечном итоге транзакция владения завершается и освобождает блокировку, а затем запрашивающая транзакция предоставляется блокировка и продолжается. Взаимоблокировки разрешаются почти сразу, в то время как блокировка может, в теории, сохраняться бесконечно. Взаимоблокировки иногда называют тупиковыми ситуациями.

Взаимоблокировка может возникать в любой системе с несколькими потоками, а не только в реляционной системе управления базами данных, и может возникать для ресурсов, отличных от блокировок объектов базы данных. Например, в многопоточной операционной системе один поток может занять один или более ресурсов, таких как блокировки памяти. Если приобретенный ресурс в настоящее время принадлежит другому потоку, первый поток может ожидать освобождения целевого ресурса. В таком случае говорят, что ожидающий поток зависит от владеющего потока для данного ресурса. В экземпляре SQL Server ядро СУБД сеансы могут взаимоблокировки при получении ресурсов, отличных от базы данных, таких как память или потоки.

Схема, показывающая взаимоблокировку транзакций.

На рисунке транзакция T1 имеет зависимость от транзакции T2 для Part ресурса блокировки таблицы. Аналогичным образом транзакция T2 имеет зависимость от транзакции T1 для Supplier ресурса блокировки таблицы. Так как эти зависимости образуют цикл, между транзакциями T1 и T2 возникает взаимоблокировка.

Взаимоблокировки также могут возникать, если таблица секционирована, а LOCK_ESCALATION для параметра задано значение ALTER TABLE AUTO. Если LOCK_ESCALATION задано значение AUTO, параллелизм увеличивается, позволяя SQL Server ядро СУБД блокировать секции таблиц на уровне HoBT, а не на уровне таблицы. Однако если отдельные транзакции удерживают блокировки секций в таблице и пытаются заблокировать еще какой-либо объект в разделе, принадлежащем другой транзакции, это вызовет взаимоблокировку. Этот тип взаимоблокировки можно избежать, установив для TABLEпараметра LOCK_ESCALATION значение . Однако этот параметр снижает параллелизм, заставляя большие обновления секции ждать блокировки таблицы.

Обнаружение и завершение взаимоблокировок

Взаимоблокировка возникает, когда две или более задачи постоянно блокируют друг друга из-за того, что задача каждой из сторон блокирует ресурс, который пытаются заблокировать другие задачи. На следующем графике приведена общая схема состояния взаимоблокировки, в которой:

  • Задача T1 имеет блокировку ресурса R1 (указанная стрелкой от R1 к T1) и запросила блокировку ресурса R2 (указанная стрелкой от T1 до R2).

  • Задача T2 имеет блокировку ресурса R2 (указанная стрелкой из R2 в T2) и запросила блокировку ресурса R1 (указана стрелка из T2 в R1).

  • Так как ни одна из задач не может продолжиться до тех пор, пока не освободится ресурс, а ни один из ресурсов не может быть освобожден до тех пор, пока не продолжится задание, существует состояние взаимоблокировки.

    Схема, показывающая задачи в состоянии взаимоблокировки.

SQL Server ядро СУБД автоматически обнаруживает циклы взаимоблокировки в SQL Server. SQL Server ядро СУБД выбирает один из сеансов в качестве жертвы взаимоблокировки, а текущая транзакция завершается ошибкой, чтобы разорвать взаимоблокировку.

Ресурсы, которые могут взаимоблокировки

У каждого сеанса пользователя может быть одна или несколько задач, выполняемых от его имени, где каждая задача может получить или ждать получения ресурсов. Следующие типы ресурсов могут привести к блокировке, которая может привести к взаимоблокировке.

  • Блокировки. Ожидание получения блокировок ресурсов, таких как объекты, страницы, строки, метаданные и приложения, могут вызвать взаимоблокировку. Например, транзакция T1 применила общую (S) блокировку строки r1 и ожидает монопольную (X) блокировку строки r2. Транзакция T2 применила общую (S) блокировку строки r2 и ожидает монопольную (X) блокировку строки r1. В результате получается цикл блокировки, в котором T1 и T2 ожидают, пока одна транзакция освободит заблокированный другой транзакцией ресурс.

  • Рабочие потоки. Задача в очереди, ожидая доступного рабочего потока, может привести к взаимоблокировке. Если задача в очереди владеет ресурсами, блокирующими все рабочие потоки, результаты взаимоблокировки. Например, сеанс S1 запускает транзакцию и применяет общую (S) блокировку строки r1, а затем уходит в спящий режим. Активные сеансы, запущенные на всех доступных рабочих потоках, делают попытки применить монопольную блокировку (X) строки r1. Так как сеанс S1 не может получить рабочий поток, он не может зафиксировать транзакцию и освободить блокировку строки r1. Возникает взаимоблокировка.

  • Memory. Если одновременные запросы ожидают предоставления памяти, которые не могут быть удовлетворены доступной памятью, может возникнуть взаимоблокировка. Например, два параллельных запроса Q1 и Q2 выполняются как определяемые пользователем функции, использующие 10 МБ и 20 МБ памяти соответственно. Если каждому запросу требуется 30 МБ, а общая доступная память составляет 20 МБ, то Q1 и Q2 должны ждать, чтобы освободить память, что приводит к взаимоблокировке.

  • Ресурсы, связанные с параллельным выполнением запросов. Координатор, производитель или потоки потребителей, связанные с портом обмена, могут блокировать друг друга, вызывая взаимоблокировку, как правило, при включении хотя бы одного другого процесса, который не является частью параллельного запроса. Кроме того, при запуске параллельного запроса SQL Server определяет степень параллелизма или количество рабочих потоков на основе текущей рабочей нагрузки. При неожиданном изменении системной рабочей нагрузки, например когда начинается выполнение на сервере новых запросов или системе не хватает потоков исполнителя, может возникать взаимоблокировка.

  • Ресурсы режима MARS. Эти ресурсы используются для управления чередованием активных запросов в режиме MARS. Дополнительные сведения см. в статье Об использовании нескольких активных результирующих наборов (MARS) в собственном клиенте SQL Server.

    • Пользовательский ресурс. Если поток ожидает ресурс, потенциально контролируемый пользовательским приложением, ресурс считается внешним или пользовательским и рассматривается как заблокированный.

    • Объект взаимного исключения сеанса. Задачи, выполняемые в одном сеансе, чередуются. Это означает, что только одна задача сеанса может выполняться в данный момент времени. Перед тем как задача может быть запущена на выполнение, она должна получить монопольный доступ к объекту взаимного исключения сеанса.

    • Объект взаимного исключения транзакции. Все задачи, выполняемые в одной транзакции, чередуются. Это означает, что только одна задача транзакции может выполняться в данный момент времени. Перед тем как задача может быть запущена на выполнение, она должна получить монопольный доступ к объекту взаимного исключения транзакции.

      Чтобы задача могла быть запущена в режиме MARS, она должна занять объект взаимного исключения сеанса. Если задача выполняется в транзакции, она должна занять объект взаимного исключения транзакции. Этим гарантируется то, что только одна задача будет активна в каждый момент времени данного сеанса и данной транзакции. Как только потребуются необходимые объекты взаимного исключения, задача сможет выполняться. Когда задача завершится или возвращается в середине запроса, она сначала освобождает мьютекс транзакции, за которым следует мьютекс сеанса, в обратном порядке приобретения. Однако взаимоблокировки могут произойти и с этими ресурсами. В следующем псевдокоде две задачи, запрос пользователя U1 и запрос пользователя U2, выполняются в одном сеансе.

      U1:    Rs1=Command1.Execute("insert sometable EXEC usp_someproc");
      U2:    Rs2=Command2.Execute("select colA from sometable");
      

      Хранимая процедура, выполняемая запросом пользователя U1, заняла объект взаимного исключения сеанса. Если хранимая процедура занимает много времени для выполнения, предполагается, что sql Server ядро СУБД, что хранимая процедура ожидает ввода от пользователя. Запрос пользователя U2 ожидает освобождения объекта взаимного исключения сеанса, в то время как пользователь ожидает результирующий набор от U2, а U1 ожидает пользовательский ресурс. Это состояние взаимоблокировки логически представляется так:

      Схема логического потока хранимой процедуры в MARS.

Обнаружение взаимоблокировок

Все ресурсы, перечисленные в разделе "Ресурсы", которые могут выполнять взаимоблокировку, участвуют в схеме обнаружения взаимоблокировок SQL Server ядро СУБД. Обнаружение взаимоблокировки выполняется потоком монитора блокировки, который периодически инициирует поиск по всем задачам в экземпляре SQL Server ядро СУБД. Следующие пункты описывают процесс поиска:

  • Значение интервала по умолчанию составляет 5 секунд.

  • Если поток монитора блокировки находит взаимоблокировки, интервал обнаружения взаимоблокировки отпадает от 5 секунд до 100 миллисекунд в зависимости от частоты взаимоблокировок.

  • Если поток монитора блокировки перестает находить взаимоблокировки, SQL Server ядро СУБД увеличивает интервалы между поиском до 5 секунд.

  • Если обнаружен взаимоблокировка, предполагается, что следующие потоки, которые должны ожидать блокировки, вводят цикл взаимоблокировки. Первые несколько блокировок ожидается после обнаружения взаимоблокировки немедленно срабатывает поиск взаимоблокировок, а не ожидает следующего интервала обнаружения взаимоблокировок. Например, если текущий интервал равен 5 секундам, а взаимоблокировка была обнаружена, следующее ожидание блокировки немедленно запускает детектор взаимоблокировки. Если это ожидание блокировки является частью взаимоблокировки, оно обнаруживается сразу, а не во время следующего поиска взаимоблокировок.

Sql Server ядро СУБД обычно выполняет периодическое обнаружение взаимоблокировок. Так как число взаимоблокировок, произошедших в системе, обычно мало, периодическое обнаружение взаимоблокировок помогает сократить издержки от взаимоблокировок в системе.

Если монитор блокировок запускает поиск взаимоблокировок для определенного потока, он идентифицирует ресурс, ожидаемый потоком. Затем монитор блокировки находит владельцев для этого конкретного ресурса и рекурсивно продолжает поиск взаимоблокировок для этих потоков, пока не обнаружит цикл. Цикл, определенный таким способом, формирует взаимоблокировку.

После обнаружения взаимоблокировки SQL Server ядро СУБД завершает взаимоблокировку, выбрав один из потоков в качестве жертвы взаимоблокировки. SQL Server ядро СУБД завершает выполнение текущего пакета для потока, откатывает транзакцию жертвы взаимоблокировки и возвращает ошибку 1205 в приложение. Откат транзакции жертвы взаимоблокировки снимает все блокировки, удерживаемые транзакцией. Это позволяет транзакциям потоков разблокироваться и продолжить выполнение. Ошибка 1205 жертвы взаимоблокировки записывает в журнал ошибок сведения обо всех потоках и ресурсах, затронутых взаимоблокировкой.

По умолчанию SQL Server ядро СУБД выбирает в качестве жертвы взаимоблокировки сеанс, выполняющий транзакцию, которая является наименее дорогой для отката. В качестве альтернативы пользователь может указать приоритет сеансов в ситуации взаимоблокировки, используя инструкцию SET DEADLOCK_PRIORITY. DEADLOCK_PRIORITY может быть задано LOWзначение , NORMALили ( или HIGH) можно задать любое целое значение в диапазоне (–10 – 10). Приоритет взаимоблокировки по умолчанию.NORMAL Если у двух сеансов имеются различные приоритеты в случае взаимоблокировки, то в качестве жертвы взаимоблокировки будет выбран сеанс с более низким приоритетом. Если у обоих сеансов установлен одинаковый приоритет в случае взаимоблокировки, то в качестве объекта взаимоблокировки будет выбран сеанс, откат которого потребует наименьших затрат. Если сеансы, вовлеченные в цикл взаимоблокировки, имеют один и тот же приоритет в случае взаимоблокировки и одинаковую стоимость, то жертва взаимоблокировки выбирается случайным образом.

При работе с средой CLR монитор взаимоблокировки автоматически обнаруживает взаимоблокировку для ресурсов синхронизации (мониторов, блокировки чтения и записи и соединения потоков), доступ к которым осуществляется внутри управляемых процедур. Однако взаимоблокировка снимается путем создания сообщения об исключительной ситуации в процедуре, которая была выбрана в качестве жертвы взаимоблокировки. Важно понимать, что исключение не освобождает ресурсы, принадлежащие в настоящее время жертве, автоматически; Ресурсы должны быть явно освобождены. В соответствии с поведением исключения, исключение, используемое для идентификации жертвы взаимоблокировки, может быть поймано и отклонено.

Средства сведений о взаимоблокировок

Для просмотра сведений о взаимоблокировке SQL Server ядро СУБД предоставляет средства мониторинга в виде сеанса system_health XEvent, двух флагов трассировки и события графа взаимоблокировки в SQL Profiler.

Примечание.

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

Расширенное событие взаимоблокировки

В SQL Server 2012 (11.x) и более поздних версиях xml_deadlock_report следует использовать расширенное событие (XEvent) вместо класса событий Взаимоблокировки в трассировке SQL или SQL Profiler.

При возникновении system_health взаимоблокировок сеанс уже записывает все xml_deadlock_report XEvents, содержащие граф взаимоблокировки. system_health Так как сеанс включен по умолчанию, вам не нужно настраивать отдельный сеанс XEvent для записи сведений о взаимоблокировке. Никаких дополнительных действий для записи сведений xml_deadlock_report о взаимоблокировке с помощью XEvent не требуется.

Зафиксированный граф взаимоблокировки обычно имеет три узла:

  • victim-list. Идентификатор процесса жертвы взаимоблокировки.
  • process-list. Сведения обо всех процессах, участвующих во взаимоблокировке.
  • resource-list. Сведения о ресурсах, участвующие во взаимоблокировке.

Открытие файла сеанса system_health или кольцевого буфера, если xml_deadlock_report XEvent записано, Management Studio представляет графическое изображение задач и ресурсов, участвующих в взаимоблокировке, как показано в следующем примере:

Снимок экрана: SSMS визуальной диаграммы графа XEvent Deadlock.

Следующий запрос может просматривать все события взаимоблокировки, захваченные буфером кольца сеансов system_health :

SELECT xdr.value('@timestamp', 'datetime') AS [Date],
       xdr.query('.') AS [Event_Data]
FROM (SELECT CAST ([target_data] AS XML) AS Target_Data
      FROM sys.dm_xe_session_targets AS xt
           INNER JOIN sys.dm_xe_sessions AS xs
               ON xs.address = xt.event_session_address
      WHERE xs.name = N'system_health'
            AND xt.target_name = N'ring_buffer') AS XML_Data
      CROSS APPLY Target_Data.nodes('RingBufferTarget/event[@name="xml_deadlock_report"]') AS XEventData(xdr)
ORDER BY [Date] DESC;

Результирующий набор:

Снимок экрана: SSMS system_health результата запроса XEvent.

В следующем примере показаны выходные данные после выбора ссылки в Event_Data первой строке результата:

<event name="xml_deadlock_report" package="sqlserver" timestamp="2022-02-18T08:26:24.698Z">
  <data name="xml_report">
    <type name="xml" package="package0" />
    <value>
      <deadlock>
        <victim-list>
          <victimProcess id="process27b9b0b9848" />
        </victim-list>
        <process-list>
          <process id="process27b9b0b9848" taskpriority="0" logused="0" waitresource="KEY: 5:72057594214350848 (1a39e6095155)" waittime="1631" ownerId="11088595" transactionname="SELECT" lasttranstarted="2022-02-18T00:26:23.073" XDES="0x27b9f79fac0" lockMode="S" schedulerid="9" kpid="15336" status="suspended" spid="62" sbid="0" ecid="0" priority="0" trancount="0" lastbatchstarted="2022-02-18T00:26:22.893" lastbatchcompleted="2022-02-18T00:26:22.890" lastattention="1900-01-01T00:00:00.890" clientapp="SQLCMD" hostname="ContosoServer" hostpid="7908" loginname="CONTOSO\user" isolationlevel="read committed (2)" xactid="11088595" currentdb="5" lockTimeout="4294967295" clientoption1="538968096" clientoption2="128056">
            <executionStack>
              <frame procname="AdventureWorks2022.dbo.p1" line="3" stmtstart="78" stmtend="180" sqlhandle="0x0300050020766505ca3e07008ba8000001000000000000000000000000000000000000000000000000000000">
SELECT c2, c3 FROM t1 WHERE c2 BETWEEN @p1 AND @p1+    </frame>
              <frame procname="adhoc" line="4" stmtstart="82" stmtend="98" sqlhandle="0x020000006263ec01ebb919c335024a072a2699958d3fcce60000000000000000000000000000000000000000">
unknown    </frame>
            </executionStack>
            <inputbuf>
SET NOCOUNT ON
WHILE (1=1)
BEGIN
    EXEC p1 4
END
   </inputbuf>
          </process>
          <process id="process27b9ee33c28" taskpriority="0" logused="252" waitresource="KEY: 5:72057594214416384 (e5b3d7e750dd)" waittime="1631" ownerId="11088593" transactionname="UPDATE" lasttranstarted="2022-02-18T00:26:23.073" XDES="0x27ba15a4490" lockMode="X" schedulerid="6" kpid="5584" status="suspended" spid="58" sbid="0" ecid="0" priority="0" trancount="2" lastbatchstarted="2022-02-18T00:26:22.890" lastbatchcompleted="2022-02-18T00:26:22.890" lastattention="1900-01-01T00:00:00.890" clientapp="SQLCMD" hostname="ContosoServer" hostpid="15316" loginname="CONTOSO\user" isolationlevel="read committed (2)" xactid="11088593" currentdb="5" lockTimeout="4294967295" clientoption1="538968096" clientoption2="128056">
            <executionStack>
              <frame procname="AdventureWorks2022.dbo.p2" line="3" stmtstart="76" stmtend="150" sqlhandle="0x03000500599a5906ce3e07008ba8000001000000000000000000000000000000000000000000000000000000">
UPDATE t1 SET c2 = c2+1 WHERE c1 = @p    </frame>
              <frame procname="adhoc" line="4" stmtstart="82" stmtend="98" sqlhandle="0x02000000008fe521e5fb1099410048c5743ff7da04b2047b0000000000000000000000000000000000000000">
unknown    </frame>
            </executionStack>
            <inputbuf>
SET NOCOUNT ON
WHILE (1=1)
BEGIN
    EXEC p2 4
END
   </inputbuf>
          </process>
        </process-list>
        <resource-list>
          <keylock hobtid="72057594214350848" dbid="5" objectname="AdventureWorks2022.dbo.t1" indexname="cidx" id="lock27b9dd26a00" mode="X" associatedObjectId="72057594214350848">
            <owner-list>
              <owner id="process27b9ee33c28" mode="X" />
            </owner-list>
            <waiter-list>
              <waiter id="process27b9b0b9848" mode="S" requestType="wait" />
            </waiter-list>
          </keylock>
          <keylock hobtid="72057594214416384" dbid="5" objectname="AdventureWorks2022.dbo.t1" indexname="idx1" id="lock27afa392600" mode="S" associatedObjectId="72057594214416384">
            <owner-list>
              <owner id="process27b9b0b9848" mode="S" />
            </owner-list>
            <waiter-list>
              <waiter id="process27b9ee33c28" mode="X" requestType="wait" />
            </waiter-list>
          </keylock>
        </resource-list>
      </deadlock>
    </value>
  </data>
</event>

Дополнительные сведения см. в разделе "Использование сеанса system_health"

Флаги трассировки 1204 и 1222

При возникновении взаимоблокировок флаг трассировки 1204 и флаг трассировки 1222 возвращает сведения, которые записываются в журнале ошибок SQL Server. Флаг трассировки 1204 сообщает сведения о взаимоблокировке, отформатированные каждым узлом, участвующим в взаимоблокировке. Флаг трассировки 1222 форматирует сведения о взаимоблокировки, сначала по процессам, а затем по ресурсам. Можно включить оба флага трассировки для получения двух представлений одного и того же события взаимоблокировки.

Внимание

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

Помимо определения свойств флага трассировки 1204 и 1222, в следующей таблице также показаны сходство и различия.

Свойство Флаги трассировки 1204 и 1222 Только флаг трассировки 1204 Только флаг трассировки 1222
Формат вывода Выходные данные записываются в журнал ошибок SQL Server. Ориентирован на узлы, участвующие во взаимоблокировке. Каждому узлу посвящен раздел, а в последнем разделе описывается пострадавший в результате взаимоблокировки объект. Возвращает сведения в формате XML, который не соответствует схеме XSD. В формате предусмотрено три основных раздела. В первом разделе объявляется пострадавший в результате взаимоблокировки объект. Во втором разделе описываются все процессы, вовлеченные во взаимоблокировку. Третий раздел описывает ресурсы, которые являются синонимами узлов в флаге трассировки 1204.
Идентифицирующие атрибуты SPID:<x> ECID:<x>. Определяет поток идентификатора системного процесса в случаях параллельных процессов. Запись SPID:<x> ECID:0, где <x> заменяется значением SPID, представляет основной поток. Запись SPID:<x> ECID:<y>, где <x> заменяется значением SPID и <y> больше 0, представляет подпотеки для того же SPID.

BatchID (sbid для флага трассировки 1222). Определяет пакет, из которого выполнение кода запрашивает или удерживает блокировку. Если режим MARS отключен, значение BatchID равно 0. Если режим MARS включен, для активных пакетов задается значение в диапазоне от 1 до n. При отсутствии активных пакетов в сеансе BatchID присваивается значение 0.

Mode Указывает тип блокировки для конкретного ресурса, запрашиваемого, предоставленного или ожидающего в потоке. Значением Mode может быть IS (с намерением совмещаемого доступа), S (совмещаемая), U (на обновление), IX (с намерением монопольного доступа), SIX (совмещаемая с намерением монопольного доступа) и X (монопольная).

Line # (line для флага трассировки 1222). Содержит номер строки в текущем пакете инструкций, который выполнялся в момент возникновения взаимоблокировки.

Input Buf (inputbuf для флага трассировки 1222). Выводит все инструкции в текущем пакете.
Node Представляет номер записи в цепочке взаимоблокировок.

Lists Владелец блокировки может быть частью этих списков:

Grant List Перечисляет текущих владельцев ресурса.

Convert List Перечисляет текущих владельцев, пытающихся преобразовать свои блокировки на более высокий уровень.

Wait List Перечисляет текущие запросы на блокировку ресурса.

Statement TypeОписывает тип инструкции DML (SELECT, илиINSERTUPDATEDELETE) для которых потоки имеют разрешения.

Victim Resource Owner Указывает участвующий поток, который SQL Server выбирает в качестве жертвы, чтобы разорвать цикл взаимоблокировки. Выбранный поток и все его подпроцессы завешены.

Next Branch Представляет два или более подпотока из одного и того же SPID, участвующих в цикле взаимоблокировки.
deadlock victim Представляет адрес физической памяти задачи (см . sys.dm_os_tasks), который был выбран в качестве жертвы взаимоблокировки. Это может быть 0 (ноль) в случае неразрешенной взаимоблокировки. Задача, которая откатывается, не может быть выбрана в качестве жертвы взаимоблокировки.

executionstack Представляет код Transact-SQL, который выполняется во время взаимоблокировки.

priority Представляет приоритет взаимоблокировки. В некоторых случаях SQL Server ядро СУБД может выбрать изменение приоритета взаимоблокировки в течение короткого времени, чтобы повысить параллелизм.

logused Пространство журнала, используемое задачей.

owner id Идентификатор транзакции, которая управляет запросом.

status Состояние задачи. Это одно из следующих значений:

- pending Ожидание рабочего потока.

- runnable Готово к выполнению, но ожидает квантовых вычислений.

- running В настоящее время выполняется на планировщике.

- suspended Выполнение приостановлено.

- done Задача завершена.

- spinloop Дождитесь того, чтобы спин-блокировка стала бесплатной.

waitresource Ресурс, необходимый задачей.

waittime Время в миллисекундах, ожидающих ресурса.

schedulerid Планировщик, связанный с этой задачей. См . sys.dm_os_schedulers.

hostname Имя рабочей станции.

isolationlevel Текущий уровень изоляции транзакций.

Xactid Идентификатор транзакции, которая управляет запросом.

currentdb Идентификатор базы данных.

lastbatchstarted При последнем запуске клиентского процесса пакетного выполнения.

lastbatchcompleted При последнем выполнении пакетного выполнения процесса клиента.

clientoption1 и clientoption2 задайте параметры для этого подключения клиента. Это битовая маска, которая содержит сведения о параметрах, обычно контролируемых операторами SET, такими как SET NOCOUNT и SET XACTABORT.

associatedObjectId Представляет идентификатор HoBT (куча или дерево B-дерева).
Атрибуты ресурсов RID определяет одну строку в таблице, в которой удерживается или запрашивается блокировка. RID представлен как RID: db_id:file_id:page_no:row_no Например, RID: 6:1:20789:0.

OBJECT определяет таблицу, на которой удерживается или запрашивается блокировка. OBJECT представляется как OBJECT: db_id:object_id. Например, TAB: 6:2009058193.

KEY Определяет диапазон ключей в индексе, на котором удерживается или запрашивается блокировка. КЛЮЧ представлен как KEY: db_id:hobt_id (хэш-значение ключа индекса). Например, KEY: 6:72057594057457664 (350007a4d329).

PAG Определяет ресурс страницы, на котором хранится блокировка или запрашивается. PAG представляется как PAG: db_id:file_id:page_no Например, PAG: 6:1:20789.

EXT Определяет структуру экстентов. EXT представлен как EXT: db_id:file_id:extent_no. Например, EXT: 6:1:9.

DB Определяет блокировку базы данных. DB представлен одним из следующих способов:

ДБ: db_id

База данных: db_id[BULK-OP-DB]идентифицирует блокировку базы данных, взятую базой данных резервной копии.

База данных: db_id[BULK-OP-LOG], которая идентифицирует блокировку, взятую журналом резервного копирования для этой конкретной базы данных.

APP Определяет блокировку, взятую ресурсом приложения. APP представлено как APP: lock_resource Например, APP: Formf370f478.

METADATA Представляет ресурсы метаданных, участвующие в взаимоблокировке. Так как METADATA имеет много подресурсов, возвращаемое значение зависит от подресурса, который заблокирован. Например, METADATA.USER_TYPE возвращает user_type_id = *integer_value*. Дополнительные сведения о ресурсах и подресурсах см. в METADATA sys.dm_tran_locks.

HOBT Представляет кучу или дерево B-дерева, участвующие в взаимоблокировке.
Немонопольно для этого флага трассировки. Немонопольно для этого флага трассировки.

Пример флага трассировки 1204

В следующем примере показаны выходные данные при включении флага трассировки 1204. В этом случае таблица в узле 1 — это куча без индексов, а таблица в узле 2 — это куча с некластеризованным индексом. В момент возникновения взаимоблокировки обновляется ключ индекса в узле 2.

Deadlock encountered .... Printing deadlock information
Wait-for graph

Node:1

RID: 6:1:20789:0               CleanCnt:3 Mode:X Flags: 0x2
 Grant List 0:
   Owner:0x0315D6A0 Mode: X
     Flg:0x0 Ref:0 Life:02000000 SPID:55 ECID:0 XactLockInfo: 0x04D9E27C
   SPID: 55 ECID: 0 Statement Type: UPDATE Line #: 6
   Input Buf: Language Event:
BEGIN TRANSACTION
   EXEC usp_p2
 Requested By:
   ResType:LockOwner Stype:'OR'Xdes:0x03A3DAD0
     Mode: U SPID:54 BatchID:0 ECID:0 TaskProxy:(0x04976374) Value:0x315d200 Cost:(0/868)

Node:2

KEY: 6:72057594057457664 (350007a4d329) CleanCnt:2 Mode:X Flags: 0x0
 Grant List 0:
   Owner:0x0315D140 Mode: X
     Flg:0x0 Ref:0 Life:02000000 SPID:54 ECID:0 XactLockInfo: 0x03A3DAF4
   SPID: 54 ECID: 0 Statement Type: UPDATE Line #: 6
   Input Buf: Language Event:
     BEGIN TRANSACTION
       EXEC usp_p1
 Requested By:
   ResType:LockOwner Stype:'OR'Xdes:0x04D9E258
     Mode: U SPID:55 BatchID:0 ECID:0 TaskProxy:(0x0475E374) Value:0x315d4a0 Cost:(0/380)

Victim Resource Owner:
 ResType:LockOwner Stype:'OR'Xdes:0x04D9E258
     Mode: U SPID:55 BatchID:0 ECID:0 TaskProxy:(0x0475E374) Value:0x315d4a0 Cost:(0/380)

Пример флага трассировки 1222

В следующем примере показаны выходные данные при включении флага трассировки 1222. В этом случае одна таблица — это куча без индексов, а другая — это куча с некластеризованным индексом. В момент возникновения взаимоблокировки обновляется ключ индекса во второй таблице.

deadlock-list
 deadlock victim=process689978
  process-list
   process id=process6891f8 taskpriority=0 logused=868
   waitresource=RID: 6:1:20789:0 waittime=1359 ownerId=310444
   transactionname=user_transaction
   lasttranstarted=2022-02-05T11:22:42.733 XDES=0x3a3dad0
   lockMode=U schedulerid=1 kpid=1952 status=suspended spid=54
   sbid=0 ecid=0 priority=0 transcount=2
   lastbatchstarted=2022-02-05T11:22:42.733
   lastbatchcompleted=2022-02-05T11:22:42.733
   clientapp=Microsoft SQL Server Management Studio - Query
   hostname=TEST_SERVER hostpid=2216 loginname=DOMAIN\user
   isolationlevel=read committed (2) xactid=310444 currentdb=6
   lockTimeout=4294967295 clientoption1=671090784 clientoption2=390200
    executionStack
     frame procname=AdventureWorks2022.dbo.usp_p1 line=6 stmtstart=202
     sqlhandle=0x0300060013e6446b027cbb00c69600000100000000000000
     UPDATE T2 SET COL1 = 3 WHERE COL1 = 1;
     frame procname=adhoc line=3 stmtstart=44
     sqlhandle=0x01000600856aa70f503b8104000000000000000000000000
     EXEC usp_p1
    inputbuf
      BEGIN TRANSACTION
       EXEC usp_p1
   process id=process689978 taskpriority=0 logused=380
   waitresource=KEY: 6:72057594057457664 (350007a4d329)
   waittime=5015 ownerId=310462 transactionname=user_transaction
   lasttranstarted=2022-02-05T11:22:44.077 XDES=0x4d9e258 lockMode=U
   schedulerid=1 kpid=3024 status=suspended spid=55 sbid=0 ecid=0
   priority=0 transcount=2 lastbatchstarted=2022-02-05T11:22:44.077
   lastbatchcompleted=2022-02-05T11:22:44.077
   clientapp=Microsoft SQL Server Management Studio - Query
   hostname=TEST_SERVER hostpid=2216 loginname=DOMAIN\user
   isolationlevel=read committed (2) xactid=310462 currentdb=6
   lockTimeout=4294967295 clientoption1=671090784 clientoption2=390200
    executionStack
     frame procname=AdventureWorks2022.dbo.usp_p2 line=6 stmtstart=200
     sqlhandle=0x030006004c0a396c027cbb00c69600000100000000000000
     UPDATE T1 SET COL1 = 4 WHERE COL1 = 1;
     frame procname=adhoc line=3 stmtstart=44
     sqlhandle=0x01000600d688e709b85f8904000000000000000000000000
     EXEC usp_p2
    inputbuf
      BEGIN TRANSACTION
        EXEC usp_p2
  resource-list
   ridlock fileid=1 pageid=20789 dbid=6 objectname=AdventureWorks2022.dbo.T2
   id=lock3136940 mode=X associatedObjectId=72057594057392128
    owner-list
     owner id=process689978 mode=X
    waiter-list
     waiter id=process6891f8 mode=U requestType=wait
   keylock hobtid=72057594057457664 dbid=6 objectname=AdventureWorks2022.dbo.T1
   indexname=nci_T1_COL1 id=lock3136fc0 mode=X
   associatedObjectId=72057594057457664
    owner-list
     owner id=process6891f8 mode=X
    waiter-list
     waiter id=process689978 mode=U requestType=wait

Событие графа взаимоблокировки Profiler

Событие в SQL Profiler, которое представляет собой графическое описание задач и ресурсов, вовлеченных во взаимоблокировку. Следующий пример иллюстрирует результаты, выводимые компонентом SQL Profiler, когда включено событие Deadlock Graph.

Внимание

Sql Profiler создает трассировки, которые были устарели в 2016 году и заменены расширенными событиями. Расширенные события имеют гораздо меньше затрат на производительность и гораздо более настраиваются, чем трассировки. Рекомендуется использовать событие взаимоблокировки расширенных событий вместо трассировок.

Снимок экрана: SSMS визуального графа взаимоблокировки из трассировки SQL.

Дополнительные сведения о событии взаимоблокировки см. в разделе Класс событий Lock:Deadlock. Дополнительные сведения о запуске графа взаимоблокировки SQL Profiler см. в разделе "Сохранение графов взаимоблокировки" (SQL Server Profiler).

Существуют эквиваленты для классов событий трассировки SQL в расширенных событиях, см. раздел "Просмотр эквивалентов расширенных событий для классов событий трассировки SQL". Расширенные события рекомендуется использовать для трассировки SQL.

Обработка взаимоблокировок

Когда экземпляр SQL Server ядро СУБД выбирает транзакцию в качестве жертвы взаимоблокировки, он завершает текущий пакет, откатывает транзакцию и возвращает сообщение об ошибке 1205 в приложение.

Your transaction (process ID #52) was deadlocked on {lock | communication buffer | thread} resources with another process and has been chosen as the deadlock victim. Rerun your transaction.

Так как любое приложение, отправляющее запросы Transact-SQL, можно выбрать в качестве жертвы взаимоблокировки, приложения должны иметь обработчик ошибок, который может перехватать сообщение об ошибке 1205. Если приложение не перехватывает ошибку, приложение может не знать, что его транзакция была откатена и могут возникнуть ошибки.

Благодаря обработчику ошибки 1205 приложение сможет справиться с взаимоблокировкой и предпринять действия по ее исправлению (например автоматически повторить запрос, который не был выполнен из-за взаимоблокировки). Если повторное выполнение запроса происходит автоматически, пользователю не обязательно знать о возникновении взаимоблокировки.

Прежде чем повторять запрос, следует приостановить приложение на короткое время. Это позволит второй участвующей транзакции закончить работу и освободить блокировки, которые частично создавали взаимоблокировку. Благодаря этому приложение минимизирует вероятность повторного возникновения взаимоблокировки при повторном выполнении запроса.

Обработка с помощью TRY... ЛОВИТЬ

Вы можете использовать TRY... CATCH для обработки взаимоблокировок. Ошибка жертвы взаимоблокировки 1205 может быть поймана блоком CATCH , и транзакция может быть откатена до тех пор, пока потоки не будут разблокированы.

Дополнительные сведения см. в разделе "Обработка взаимоблокировок".

Минимизация взаимоблокировок

Хотя полностью избежать взаимоблокировок нельзя, следующие соглашения по написанию кода могут уменьшить вероятность возникновения взаимоблокировок. Минимизация взаимоблокировок приводит к увеличению пропускной способности системы (выполнению большего количества транзакций за единицу времени) и уменьшению накладных расходов системы на обслуживание, так как транзакции реже:

  • Откатываются с отменой всей выполненной транзакцией работы.
  • Повторно выполняются приложениями, так как при возникновении взаимоблокировок они откатывались.

Для минимизации взаимоблокировок:

  • Осуществляйте доступ к объектам в одинаковом порядке.
  • Избегайте взаимодействия с пользователем в транзакциях.
  • Уменьшайте размер транзакций, желательно помещая их в один пакет.
  • Используйте низкий уровень изоляции.
  • Используйте уровень изоляции строк, основанный на управлении версиями строк.
    • Установите для параметра базы данных READ_COMMITTED_SNAPSHOT значение ON, чтобы разрешить транзакциям с зафиксированным чтением использовать управление версиями строк.
    • Используйте изоляцию моментальных снимков.
  • Используйте связанные соединения.

Осуществление доступа к объектам в одинаковом порядке

Если все одновременные транзакции будут осуществлять доступ к объектам в одинаковом порядке, то появление взаимоблокировок менее вероятно. Например, если две параллельные транзакции получают блокировку Supplier таблицы, а затем в Part таблице одна транзакция блокируется в Supplier таблице, пока не завершится другая транзакция. После фиксации первой транзакции или отката второй продолжается, а взаимоблокировка не возникает. Использование хранимых процедур для всех изменений данных может стандартизировать порядок доступа к объектам.

Схема взаимоблокировки.

Отказ от взаимодействия с пользователем в транзакциях

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

Уменьшение размера транзакций и хранение их в одном пакете

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

Помещение транзакций в один пакет сокращает объемы передачи данных по сети во время транзакции, уменьшая возможные задержки при завершении транзакций и снятии блокировок.

Дополнительные сведения о блокировках обновлений см . в руководстве по блокировке транзакций и управлении версиями строк.

Использование низкого уровня изоляции

Определите, может ли транзакция выполняться при более низком уровне изоляции. Применение фиксации чтением позволяет транзакции считывать данные, считанные до этого (но не измененные) другой транзакцией, не ожидая завершения выполнения этой другой транзакции. Более низкий уровень изоляции, например зафиксированный для чтения, содержит общие блокировки в течение более короткой длительности, чем более высокий уровень изоляции, например сериализуемый. Это уменьшает количество состязаний блокировок.

Использование уровня изоляции, основанного на управлении версиями строк

READ_COMMITTED_SNAPSHOT Если установлен ONпараметр базы данных, транзакция, выполняемая на уровне изоляции с фиксацией чтения, использует управление версиями строк, а не общие блокировки во время операций чтения.

Примечание.

Некоторые приложения зависят от блокировок и монополизации ресурсов, обеспечиваемых уровнем изоляции read committed. В такие приложения перед включением данного параметра необходимо внести изменения.

Изоляция моментальных снимков также использует управление версиями строк, которая не использует общие блокировки во время операций чтения. Прежде чем транзакция может выполняться при изоляции моментального снимка, ALLOW_SNAPSHOT_ISOLATION необходимо задать ONпараметр базы данных.

Применение этих уровней изоляции приводит к минимизации взаимоблокировок, возникающих между операциями считывания и записи.

Использование связанных соединений

При использовании связанных соединений два или более соединения, открытые одним и тем же приложением, могут действовать совместно друг с другом. Любые блокировки, используемые вторичными соединениями, устанавливаются так, как если бы они запрашивались первичным соединением, и наоборот. Поэтому они не блокируют друг друга.

Остановка транзакции

В сценарии взаимоблокировки транзакция жертвы автоматически останавливается и откатывается. Нет необходимости останавливать транзакцию в сценарии взаимоблокировки.

Причина взаимоблокировки

Примечание.

Этот пример работает в AdventureWorksLT2019 примере базы данных с схемой и данными по умолчанию при включении READ_COMMITTED_SNAPSHOT. Чтобы скачать этот пример, посетите примеры баз данных AdventureWorks.

Чтобы вызвать взаимоблокировку, необходимо подключить два сеанса AdventureWorksLT2019 к базе данных. Мы называем эти сеансы сеансами A и сеансом B. Эти два сеанса можно создать, просто создав два окна запросов в SQL Server Management Studio (SSMS).

В Сеансе A выполните следующую инструкцию Transact-SQL. Этот код начинает явную транзакцию и запускает одну инструкцию, которая обновляет таблицу SalesLT.Product. Для этого транзакция получает блокировку обновления (U) для одной строки в таблице SalesLT.Product, которая преобразуется в монопольную блокировку (X). Мы оставим транзакцию открытой.

BEGIN TRANSACTION;

UPDATE SalesLT.Product
    SET SellEndDate = SellEndDate + 1
WHERE Color = 'Red';

Теперь в Сеансе B выполните следующую инструкцию Transact-SQL. Этот код не запускает транзакцию явным образом. Вместо этого он работает в режиме автофиксации транзакции. Эта инструкция обновляет таблицу SalesLT.ProductDescription. Обновление удаляет блокировку обновления (U) на 72 строках SalesLT.ProductDescription таблицы. Запрос присоединяется к другим таблицам, включая таблицу SalesLT.Product.

UPDATE SalesLT.ProductDescription
    SET Description = Description
FROM SalesLT.ProductDescription AS pd
     INNER JOIN SalesLT.ProductModelProductDescription AS pmpd
         ON pd.ProductDescriptionID = pmpd.ProductDescriptionID
     INNER JOIN SalesLT.ProductModel AS pm
         ON pmpd.ProductModelID = pm.ProductModelID
     INNER JOIN SalesLT.Product AS p
         ON pm.ProductModelID = p.ProductModelID
WHERE p.Color = 'Silver';

Чтобы завершить это обновление, сеанс B требует общей блокировки (S) для строк в таблице SalesLT.Product, включая строку, заблокированную сеансом A. Сеанс B заблокирован SalesLT.Product.

Вернитесь к Сеансу А. Выполните следующую инструкцию Transact-SQL. Это запускает вторую UPDATE инструкцию в рамках открытой транзакции.

UPDATE SalesLT.ProductDescription
    SET Description = Description
FROM SalesLT.ProductDescription AS pd
     INNER JOIN SalesLT.ProductModelProductDescription AS pmpd
         ON pd.ProductDescriptionID = pmpd.ProductDescriptionID
     INNER JOIN SalesLT.ProductModel AS pm
         ON pmpd.ProductModelID = pm.ProductModelID
     INNER JOIN SalesLT.Product AS p
         ON pm.ProductModelID = p.ProductModelID
WHERE p.Color = 'Red';

Вторая инструкция обновления в сеансе A блокируется сеансом B в .SalesLT.ProductDescription

Теперь Сеанс A и Сеанс B взаимно блокируют друг друга. Ни одна из транзакций не может быть продолжена, так как каждой из них требуется ресурс, заблокированный другой транзакцией.

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

Msg 1205, Level 13, State 51, Line 7
Transaction (Process ID 51) was deadlocked on lock resources with another process and has been chosen as the deadlock victim. Rerun the transaction.

Если взаимоблокировка не возникает, убедитесь, что READ_COMMITTED_SNAPSHOT включена в образце базы данных. Взаимоблокировки могут возникать в любой конфигурации базы данных, но в этом примере требуется включить READ_COMMITTED_SNAPSHOT эту блокировку.

Затем можно просмотреть сведения о взаимоблокировке в целевом объекте system_health ring_buffer сеанса расширенных событий, который включен и активен по умолчанию в SQL Server. Обратите внимание на следующий запрос:

WITH cteDeadLocks ([Deadlock_XML])
AS (SELECT CAST (target_data AS XML) AS [Deadlock_XML]
    FROM sys.dm_xe_sessions AS xs
         INNER JOIN sys.dm_xe_session_targets AS xst
             ON xs.[address] = xst.event_session_address
    WHERE xs.[name] = 'system_health'
          AND xst.target_name = 'ring_buffer')
SELECT x.Graph.query('(event/data/value/deadlock)[1]') AS Deadlock_XML,
       x.Graph.value('(event/data/value/deadlock/process-list/process/@lastbatchstarted)[1]', 'datetime2(3)') AS when_occurred,
       DB_Name(x.Graph.value('(event/data/value/deadlock/process-list/process/@currentdb)[1]', 'int')) AS DB --Current database of the first listed process
FROM (SELECT Graph.query('.') AS Graph
      FROM cteDeadLocks AS c
      CROSS APPLY c.[Deadlock_XML].nodes('RingBufferTarget/event[@name="xml_deadlock_report"]') AS Deadlock_Report(Graph)) AS x
ORDER BY when_occurred DESC;

Xml можно просмотреть в столбце Deadlock_XML внутри SSMS, выбрав ячейку, которая отображается в виде гиперссылки. Сохраните эти выходные .xdl данные в виде файла, закройте, а затем снова откройте .xdl файл в SSMS для визуального графа взаимоблокировки. Граф взаимоблокировки должен выглядеть примерно так, как показано на следующем рисунке.

Снимок экрана: граф взаимоблокировки визуального элемента в XDL-файле в SSMS.

Оптимизированная блокировка и взаимоблокировка

Область применения: База данных SQL Azure

Оптимизированная блокировка представила другой метод для механики блокировки, которая изменяет, как взаимоблокировки с участием эксклюзивных блокировок TID могут быть сообщены. В каждом ресурсе в отчете <resource-list>взаимоблокировки каждый <xactlock> элемент сообщает базовые ресурсы и конкретную информацию о блокировках каждого члена взаимоблокировки.

Рассмотрим следующий пример, в котором включена оптимизированная блокировка:

CREATE TABLE t2
(
    a INT PRIMARY KEY NOT NULL,
    b INT NULL
);

INSERT INTO t2
VALUES (1, 10),
(2, 20),
(3, 30);
GO

Следующие команды Transact-SQL в двух сеансах создают взаимоблокировку в таблице t2:

В сеансе 1:

--session 1
BEGIN TRANSACTION foo;

UPDATE t2
    SET b = b + 10
WHERE a = 1;

В сеансе 2:

--session 2:
BEGIN TRANSACTION bar;

UPDATE t2
    SET b = b + 10
WHERE a = 2;

В сеансе 1:

--session 1:
UPDATE t2
    SET b = b + 100
WHERE a = 2;

В сеансе 2:

--session 2:
UPDATE t2
    SET b = b + 20
WHERE a = 1;

Этот сценарий конкурирующих UPDATE операторов приводит к взаимоблокировке. В этом случае ресурс блокировки ключей, где каждый сеанс содержит блокировку X на своем собственном TID и ожидает блокировки S на другом TID, что приводит к взаимоблокировке. Следующий XML-код, захваченный как отчет взаимоблокировки, содержит элементы и атрибуты, относящиеся к оптимизированной блокировке:

Снимок экрана: XML-файл отчета взаимоблокировки, показывающий узлы БазовыхResource и узлы блокировки ключей, относящиеся к оптимизированной блокировке.