Проблема взаимоблокировки в SQL Server 2008 R2 (приложение .Net 2.0) - PullRequest
7 голосов
/ 16 сентября 2010

Рассматриваемый экземпляр Sql Server 2008 R2 является высоконагруженным рабочим сервером OLTP. Проблема тупика возникла несколько дней назад и до сих пор не решена. Мы получили отчет о взаимоблокировке Xml, в котором перечислены хранимые процедуры, связанные с тупиком, и некоторые другие подробности. Сначала я попытаюсь перечислить факты из этого xml:

Две тупые процедуры задействованы в тупике, скажем, SP1 и SP2. Согласно отчету SP1 работал на уровне изоляции «Сериализуемый» и SP2 работал на «ReadCommitted» .

Мы исследовали следующее:

  • Мы устанавливаем IsolationLevel SP1 «Сериализуемый» внутри SP или в Код? - №

  • Любой другой SP, чей IsolationLevel такое "Сериализуемый" вызов SP1? - №

  • Таблица, используемая SP1, вызывается любой другой ИП, который имеет Изоляцию Уровень как "Сериализуемый"? - Да. Есть ИП, у которых есть Изоляция Уровень установлен на «Сериализуемый» и получить доступ к тем же таблицам, что и SP1, но мы не знаем, являются ли они бежали во время тупик или нет как тупик
    отчет только показал SP1 и SP2.

Направления мысли:
Мы рассмотрели следующие возможные причины:

  • Произошла тупиковая ситуация, поскольку SP1 работает как "Сериализуемый". - Почему этот SP работает в Serializable, когда Я не установил это? Это изоляция повышение уровня (как это делают замки)? Если мы понимаем это и заставляем его работать как ReadCommitted, будет ли проблема решена?

  • Любой другой SP работает, блокируя таблица используется SP1 и вызывает тупик между SP1 и SP2. - Не будет ли этот SP указан в тупиковый отчет? Может тупик сообщить пропустить такую ​​зависимость? Если да тогда мы могли бы быть только частичными Информация. Это до сих пор не решить, как работает SP1 Сериализуемый, хотя.

Предложения:

  • Если этой информации недостаточно в решении проблемы, как я могу получить больше информации из SQL Сервер для моей цели и что информацию я должен попытаться собрать?

  • Любая другая линия мысли, которую вы бы продолжить решение этой проблемы?

Обновление:
Это информация журнала трассировки для тупика. Я изменил имена SP и т. Д., Но проверил и проверил, что изменения не пропускают любую соответствующую информацию. Проверьте примечания после кода для получения дополнительной информации о таблицах и т. Д.

?<EVENT_INSTANCE>
  <EventType>DEADLOCK_GRAPH</EventType>
  <PostTime>2010-09-07T11:27:47.870</PostTime>
  <SPID>16</SPID>
  <TextData>
    <deadlock-list>
      <deadlock victim="process5827708">
        <process-list>
          <process id="process5827708" taskpriority="0" logused="0" waitresource="KEY: 7:72057594228441088 (8d008a861f4f)"
                   waittime="5190" ownerId="1661518243" transactionname="SELECT" lasttranstarted="2010-09-07T11:27:42.657"
                   XDES="0x80bf3b50" lockMode="RangeS-S" schedulerid="4" kpid="2228" status="suspended" spid="76" sbid="0"
                   ecid="0" priority="0" trancount="0" lastbatchstarted="2010-09-07T11:27:42.657"
                   lastbatchcompleted="2010-09-07T11:27:42.657" clientapp=".Net SqlClient Data Provider"
                   hostname="xxx" hostpid="5988" loginname="xxx" isolationlevel="serializable (4)"
                   xactid="1661518243" currentdb="7" lockTimeout="4294967295" clientoption1="673185824" clientoption2="128056">
            <executionStack>
              <frame procname="SP1" line="12" stmtstart="450" stmtend="6536"
                     sqlhandle="0x0300070090cbdc7742720c00e99d00000100000000000000">
                Select ... from Table1, Table2, Table4, Table5
              </frame>
            </executionStack>
            <inputbuf>
              Proc [Database Id = 7 Object Id = 2010958736]
            </inputbuf>
          </process>
          <process id="process5844bc8" taskpriority="0" logused="1873648" waitresource="KEY: 7:72057594228441088 (0e00ce038ed0)"
                   waittime="4514" ownerId="1661509575" transactionname="user_transaction" lasttranstarted="2010-09-07T11:27:40.423"
                   XDES="0x37979ae90" lockMode="X" schedulerid="7" kpid="3260" status="suspended" spid="104" sbid="0" ecid="0"
                   priority="0" trancount="2" lastbatchstarted="2010-09-07T11:27:43.350" lastbatchcompleted="2010-09-07T11:27:43.350"
                   clientapp=".Net SqlClient Data Provider" hostname="xxx" hostpid="5988" loginname="xxx"
                   isolationlevel="read committed (2)" xactid="1661509575" currentdb="7" lockTimeout="4294967295"
                   clientoption1="673185824" clientoption2="128056">
            <executionStack>
              <frame procname="SP2" line="68" stmtstart="5272" stmtend="5598"
                     sqlhandle="0x030007003432350f109a0c00e99d00000100000000000000">
                UPDATE Table1 ...
              </frame>
            </executionStack>
            <inputbuf>
              Proc [Database Id = 7 Object Id = 255144500]
            </inputbuf>
          </process>
        </process-list>
        <resource-list>
          <keylock hobtid="72057594228441088" dbid="7" objectname="Table1" indexname="Index1"
                   id="lock448e2c580" mode="X" associatedObjectId="72057594228441088">
            <owner-list>
              <owner id="process5844bc8" mode="X" />
            </owner-list>
            <waiter-list>
              <waiter id="process5827708" mode="RangeS-S" requestType="wait" />
            </waiter-list>
          </keylock>
          <keylock hobtid="72057594228441088" dbid="7" objectname="Table1" indexname="Index1"
                   id="lock2ba335880" mode="RangeS-S" associatedObjectId="72057594228441088">
            <owner-list>
              <owner id="process5827708" mode="RangeS-S" />
            </owner-list>
            <waiter-list>
              <waiter id="process5844bc8" mode="X" requestType="wait" />
            </waiter-list>
          </keylock>
        </resource-list>
      </deadlock>
    </deadlock-list>
  </TextData>
  <TransactionID />
  <LoginName>xx</LoginName>
  <StartTime>2010-09-07T11:27:47.867</StartTime>
  <ServerName>xxx</ServerName>
  <LoginSid>xxx</LoginSid>
  <EventSequence>116538375</EventSequence>
  <IsSystem>1</IsSystem>
  <SessionLoginName />
</EVENT_INSTANCE>

SP1 выполняет выборку, которая берет данные из 5 разных таблиц (от Table1 до Table5) (использует внутренний запрос и т. Д.) SP2 выполняет обновление для Table1.
Интересно, что один из столбцов, в которых обновления SP2 - это поле внешнего ключа в Таблице 1 и первичный ключ Таблицы 2, в то время как и Таблица 1, и Таблица 2 являются частью оператора выбора SP1, не уверен, что это важно, но не хотел пропустить что-нибудь.

ПРИМЕЧАНИЕ: indexname = "Index1" (на графике взаимоблокировки выше) - Index1 находится в том же столбце, что и внешний ключ в Table1 и первичный ключ в Table2.

Ответы [ 3 ]

2 голосов
/ 02 апреля 2012

Отметьте статью MSDN , в которой говорится:

Уровень изоляции имеет область действия для всего соединения и один раз устанавливается для соединение с оператором SET TRANSACTION ISOLATION LEVEL, это остается в силе до тех пор, пока не будет закрыто соединение или другая изоляция уровень установлен. Когда соединение закрыто и возвращено в пул, уровень изоляции от последнего УСТАНОВЛЕННОГО УРОВНЯ ИЗОЛЯЦИИ Заявление сохраняется. Последующие соединения, повторно использующие объединенные Соединение использовать уровень изоляции, который был в силе в то время, когда соединение в пул.

Проблема заключалась в том, что соединение было открыто с Serializable уровнем изоляции; соответствующая транзакция была удалена, как и соединение, но соединение не было уничтожено и перешло в пул соединений. В следующий раз, когда был сделан запрос на соединение (с той же строкой соединения), само это соединение возвращалось, и, поскольку в запросе не был указан какой-либо уровень изоляции, он выполнялся на уровне изоляции Serializable.

По сути, если у вас есть пул соединений и вы открываете соединение с определенным уровнем изоляции, скажем, Serializable, то соединение вернется в пул с уровнем изоляции, установленным в Serializable. В следующий раз, когда вы запросите соединение, вы не можете быть уверены, что это соединение не будет возвращено, поэтому даже через уровень изоляции по умолчанию ReadCommitted вы можете получить одно из этих «Сериализуемых» соединений.

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

Я не нашел никакого механизма для сброса одноразового соединения (когда оно возвращалось в пул соединений после выполнения моего запроса). Одним из обходных путей является явный сброс уровня изоляции для каждого соединения. Но это утомительно.

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

1 голос
/ 08 апреля 2011

добавьте (nolock) после этих выбранных таблиц в sp1, чтобы убедиться, что нельзя добавить блокировку чтения к этим конкретным таблицам.

0 голосов
/ 10 апреля 2011

Я знаю, что в некоторых ситуациях некластеризованный индекс может вызвать тупик между SELECT и UPDATE операторами, и, похоже, это может быть уместно в вашем случае. Смотрите эти ссылки для получения дополнительной информации:

...