У нас есть сервер SQL Server 2005 (SERVER-A), на котором хранится база данных для приложения, которое в последнее время часто блокируется. Мы подозреваем, что проблема заключается в блокировках транзакций, поэтому мы решили зафиксировать некоторые следы на этом сервере с помощью SQL Server Profiler, мы начали собирать отчет о заблокированных процессах и получили следующее:
<blocked-process-report monitorLoop="3501256">
<blocked-process>
<process id="processffffffff83047a68" taskpriority="0"
logused="0" waitresource="OBJECT: 18:85575343:0 " waittime="27656"
ownerId="1540544048" transactionname="InsertCall"
lasttranstarted="2013-11-25T14:40:43.083" XDES="0x3790fad8"
lockMode="IX" schedulerid="2" kpid="6852" status="suspended"
spid="78" sbid="0" ecid="0" priority="0" transcount="2"
lastbatchstarted="2013-11-25T14:40:43.083" lastbatchcompleted="2013-11-25T14:40:43.073"
clientapp="" hostname="" hostpid="3256" loginname=""
isolationlevel="read committed (2)" xactid="1540544048" currentdb="18"
lockTimeout="4294967295" clientoption1="673185824" clientoption2="128056">
<executionStack>
<frame line="201" stmtstart="10790" stmtend="11790" sqlhandle=""/>
<frame line="1" sqlhandle=""/>
</executionStack>
<inputbuf>EXEC SomeProcedure</inputbuf>
</process>
</blocked-process>
<blocking-process>
<process status="suspended" waittime="15" spid="51" sbid="2" ecid="0" priority="0"
transcount="1" lastbatchstarted="2013-11-25T14:40:20.900"
lastbatchcompleted="2013-11-25T14:40:20.900" lastattention="2013-11-25T14:39:18.530"
clientapp="Microsoft SQL Server" hostname="SERVER-B" hostpid="1340" loginname=""
isolationlevel="read committed (2)" xactid="1540536548" currentdb="7"
lockTimeout="4294967295" clientoption1="671088672" clientoption2="128056">
<executionStack>
<frame line="1" sqlhandle=""/>
<frame line="1" sqlhandle=""/>
</executionStack>
<inputbuf>INCOMING SELECT FROM SERVER-B</inputbuf>
</process>
</blocking-process>
</blocked-process-report>
На SERVER-B есть еще один SQL Server 2008, который имеет SERVER-A в качестве связанного сервера и выполняет только удаленные операции SELECT. Итак, я не понимаю предыдущий захват, может ли удаленный выбор вызывать блокировки? И если да, то как мы можем этого предотвратить?
Если SERVER-A
был указан как «связанный сервер», то запросы к таблицам, касающиеся связанных данных, будут передаваться на SERVER-A
как будто они были казнены непосредственно против SERVER-A
. Таким образом, они, очевидно, могут вызвать блокировки.
В вашем случае с уровнем изоляции транзакции READ COMMITTED запрос SELECT будет удерживать блокировки чтения для затронутых строк (которая может быть всей таблицей) в течение всего времени выполнения запроса, эффективно предотвращая выполнение обновлений в этих строках, а также операторы, требующие блокировки для всей таблицы (например, операторы DML).
Обратите внимание, что инструкция, похоже, выполняется уже некоторое время (по крайней мере, минуту). Если у вас есть такие долго работающие селекты, блокирующие ваши обновления, рассмотрите возможность их запуска с использованием уровня изоляции транзакции SNAPSHOT
или READ UNCOMMITTED
, в зависимости от ваших требований к производительности и согласованности данных. Увидеть документы об уровнях изоляции транзакций для подробностей.
Исходя из моего ограниченного понимания этой темы, с уровнем изоляции «чтение зафиксировано» (как показано в вашем отчете о блоках) оператор SELECT получит общую блокировку текущей строки, чтобы предотвратить обновление данных во время чтения.
Это эффективно предотвращает получение транзакцией INSERT эксклюзивной блокировки указанной строки, так что да, в зависимости от ваших структур данных и параметры уровня блокировки индекса, предложение SELECT наверняка может вызвать блокировку.
Я не супер-администратор базы данных SQL, но многие люди более мудрые, чем я, писали об обходе блокировок с использованием некластеризованного индексного покрытия. я обнаружил эта конкретная статья очень поучительно