我们有一个 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 DBA,但很多比我聪明的人都写过关于使用非聚集索引覆盖绕过锁的文章。我发现这篇特别的文章很有教育意义