Вопрос

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

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

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

  • Мы устанавливаем изоляцию SP1 для «сериализуемого» внутри SP или в коде?- Нет.

  • Является ли какой -либо другой SP, чей изоляционной комплекс «сериализуем» называет SP1?- Нет.

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

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

  • Законный тупик происходит, потому что SP1 работает как «сериализуемый».- Почему этот SP работает в сериализу, когда я его не устанавливал?Уровень изоляции обостряется (как и замки)?Если мы выясним это и заработаем его как ReadCommit, будет ли проблема решена?

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

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

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

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

Обновлять:
Это информация журнала трассировки для тупика.Я изменил имена 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.

Это было полезно?

Решение

Проверь это Статья MSDN в котором говорится:

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

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

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

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

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

Поэтому лучшая альтернатива — создать отдельные пулы соединений для разных уровней изоляции..

Другие советы

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

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

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top