Почему этот запрос SQL Server блокируется? - PullRequest
1 голос
/ 03 сентября 2011

Может кто-нибудь сказать мне, почему следующие запросы SQL Server являются взаимоблокирующими и каково решение для их устранения?

<deadlock-list>
  <deadlock victim="process88b5b8">
    <process-list>
      <process id="process88b5b8" taskpriority="0" logused="76132" waitresource="RID: 32:1:151867:174" waittime="5093" ownerId="65554098" transactionguid="0xedf3314c05f1124cbe8d480cd092e03e" transactionname="DTCXact" lasttranstarted="2011-09-02T19:00:29.690" XDES="0x1029e040" lockMode="S" schedulerid="1" kpid="5108" status="suspended" spid="118" sbid="0" ecid="0" priority="0" transcount="2" lastbatchstarted="2011-09-02T19:00:31.317" lastbatchcompleted="2011-09-02T19:00:31.300" hostname="MELWFPL382S" hostpid="0" loginname="MM4" isolationlevel="repeatable read (3)" xactid="65554098" currentdb="32" lockTimeout="4294967295" clientoption1="671088672" clientoption2="128056">
        <executionStack>
          <frame procname="adhoc" line="1" stmtstart="78" sqlhandle="0x020000004b4b0a0d63e1040095143cbaa0174ffc3e076067"> delete from PARTIES where PARTYEXTERNALREF=@P0 and ISCOUNTERPARTY='N' and PARTYID in (select PARTYID from NAB_PARTY_EXTEND (nolock) where PARTYTYPE=@P1)     </frame>
          <frame procname="unknown" line="1" sqlhandle="0x000000000000000000000000000000000000000000000000">unknown     </frame>
        </executionStack>
        <inputbuf>(@P0 nvarchar(4000),@P1 nvarchar(4000))delete from PARTIES where PARTYEXTERNALREF=@P0 and ISCOUNTERPARTY='N' and PARTYID in (select PARTYID from NAB_PARTY_EXTEND (nolock) where PARTYTYPE=@P1)                    </inputbuf>
      </process>
      <process id="process9196a8" taskpriority="0" logused="132612" waitresource="RID: 32:1:140302:31" waittime="5046" ownerId="65554657" transactionguid="0x7313c78fecc8914dac3ed821cd7c21fe" transactionname="DTCXact" lasttranstarted="2011-09-02T19:00:34.100" XDES="0x12835778" lockMode="S" schedulerid="2" kpid="3692" status="suspended" spid="94" sbid="0" ecid="0" priority="0" transcount="2" lastbatchstarted="2011-09-02T19:00:35.690" lastbatchcompleted="2011-09-02T19:00:35.687" hostname="MELWFPL382S" hostpid="0" loginname="MM4" isolationlevel="repeatable read (3)" xactid="65554657" currentdb="32" lockTimeout="4294967295" clientoption1="671088672" clientoption2="128056">
        <executionStack>
          <frame procname="adhoc" line="1" stmtstart="78" sqlhandle="0x020000004b4b0a0d63e1040095143cbaa0174ffc3e076067">delete from PARTIES where PARTYEXTERNALREF=@P0 and ISCOUNTERPARTY='N' and PARTYID in (select PARTYID from NAB_PARTY_EXTEND (nolock) where PARTYTYPE=@P1)     </frame>
          <frame procname="unknown" line="1" sqlhandle="0x000000000000000000000000000000000000000000000000">unknown     </frame>
        </executionStack>
        <inputbuf>(@P0 nvarchar(4000),@P1 nvarchar(4000))delete from PARTIES where PARTYEXTERNALREF=@P0 and ISCOUNTERPARTY='N' and PARTYID in (select PARTYID from NAB_PARTY_EXTEND (nolock) where PARTYTYPE=@P1)                    </inputbuf>
      </process>
    </process-list>
    <resource-list>
      <ridlock fileid="1" pageid="140302" dbid="32" objectname="mm4_melwfpl382s.dbo.COUNTERPARTYSSI" id="lock170fa500" mode="X" associatedObjectId="72057595803336704">
        <owner-list>
          <owner id="process88b5b8" mode="X" />
        </owner-list>
        <waiter-list>
          <waiter id="process9196a8" mode="S" requestType="wait" />
        </waiter-list>
      </ridlock>
      <ridlock fileid="1" pageid="151867" dbid="32" objectname="mm4_melwfpl382s.dbo.COUNTERPARTYSSI" id="lock20e65d80" mode="X" associatedObjectId="72057595803336704">
        <owner-list>
          <owner id="process9196a8" mode="X" />
        </owner-list>
        <waiter-list>
          <waiter id="process88b5b8" mode="S" requestType="wait" />
        </waiter-list>
      </ridlock>
    </resource-list>
  </deadlock>
</deadlock-list>

Что я не понимаю, так это то, как два процесса могут иметь эксклюзивную блокировку натот же объект.

Существует индекс (IDX_NC_PARTIES_PARTYEXTERNALREF_ISCOUNTERPARTY_PARTYID) в таблице PARTIES, и база данных настроена на чтение зафиксированного снимка.

Спасибо,

Уэйн.

1 Ответ

9 голосов
/ 03 сентября 2011
  • процесс 9196a8 имеет слот страницы 151867 174 в режиме X и хочет, чтобы слот страницы 3130302 31 в режиме S
  • процесс 88b5b8 имеет слот страницы 313022 в режиме X и хочет слот 174 страницы 151867 в режиме S
  • два удаления выполняются в isolationlevel="repeatable read (3)"

Таким образом, в базовой куче таблицы возникает взаимоблокировка (блокировки RID вместо блокировок ключей подразумевают кучу, а не Btree).Высокий уровень изоляции (вероятно, вызванный DTC, судя по названию xact) делает настройку RCSI неактуальной.

Какого типа столбцы PARTYEXTERNALREF и PARTYTYPE?Передаваемыми параметрами являются NVARCHAR (т. Е. Unicode), и если столбцы VARCHAR (т. Е. Ascii), то из-за правил приоритет типа данных индекс NC не будет использоваться.Из-за задействованного сканирования таблиц и высокого уровня изоляции тупиковая ситуация практически неизбежна.

Решением будет использование параметров типа VARCHAR для @ P0 и @ P1, чтобы индекс NC использовался, чтобы избежать сканирования таблицы.

Если параметры уже имеют тип VARCHAR и выМожно из плана выполнения подтвердить, что используется поиск на ЧПУ, мой первый вопрос был бы о том, что еще делает транзакция, кроме операторов удаления?

Кстати, вы толькодайте название NC-индексу, но я предполагаю, что он (PARTYEXTERNALREF, ISCOUNTERPARTY, PARTYID).

Update

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

  • любой другой оператор, выполняемый транзакцией до УДАЛЕНИЯ (это наиболее вероятно)
  • любое перекрытие строквыбран двумя операторами DELETE, участвующими в тупике
  • коллизия хешей

Только для первых двух гипотез вы можете сделать что-либо прямо сейчас (выясните, верны ли они).Для последнего я могу рассказать вам, как это проверить, но это не тривиально.Это вряд ли случится и немного сложно доказать, но это возможно.Поскольку вы знаете о случае взаимоблокировки (прикрепленный XML), используйте его в качестве базы расследования:

  • восстановить копию базы данных на текущий момент времени с остановкой на 2011-09-02T19: 00: 29.690
  • запустить DBCC TRACEON(3604,-1)
  • с помощью DBCC PAGE (<restored db id>, 1, 151867, 3) проверить значения в слоте 174
  • с помощью DBCC PAGE (,1, 140302, 3) `проверить значения в слоте 31
  • run SELECT %%lockres%% FROM PARTIES WHERE PARTYEXTERNALREF = ... AND ISCOUNTERPARTY='N' and PARTYID=... и передать значения, показанные выше
  • сравнивает полученные значения хэша блокировки, если они совпадают, то у вас естьстолкновение хешей, и это вызвало тупик.
...