Mag*_*ier 11 sql-server deadlock sql-server-2008-r2 index-tuning locking
我正面临着一些重复发生的死锁,其中一个是 Keylock 并且包含一个带有 XLOCK 提示的 SELECT 查询,该查询成为死锁的受害者。另一个语句是对作为第一个查询视图的一部分的一个表的 INSERT。
看法:
create view dbo.viewE
as
select * from dbo.E
where myValue > 13000
Run Code Online (Sandbox Code Playgroud)
选择查询:
select * from dbo.viewE with (XLOCK) where A > GETUTCDATE()
Run Code Online (Sandbox Code Playgroud)
插入语句:
INSERT INTO [dbo].[E] (myValue,A) VALUES (10,GetDate())
Run Code Online (Sandbox Code Playgroud)
基础表 dbo.E 在大约 20 列中包含大约 300 万行,其中一些是 ntext。
取出查询并使用两个事务手动模拟它,该行为是可重现的。如果从选择中删除 XLOCK,则行为会发生变化。
死锁图:
<deadlock-list>
<deadlock victim="process222222221">
<process-list>
<process id="process222222221" taskpriority="0" logused="0" waitresource="KEY: 5:72057604035644444 (ccdf51accc0c)" waittime="2522" ownerId="27202256401" transactionname="SELECT" lasttranstarted="2015-09-14T16:32:36.160" XDES="0x2f1ec5ca0" lockMode="RangeX-X" schedulerid="15" kpid="12936" status="suspended" spid="359" sbid="0" ecid="0" priority="0" trancount="0" lastbatchstarted="2015-09-14T16:32:36.160" lastbatchcompleted="2015-09-14T16:32:36.160" clientapp="x" hostname="x" hostpid="14536" loginname="x" isolationlevel="serializable (4)" xactid="27202256401" currentdb="5" lockTimeout="4294967295" clientoption1="671088672" clientoption2="128056">
<executionStack>
<frame procname="adhoc" line="1" stmtstart="48" sqlhandle="0x02000000611e4523142b2318c47c87313a9b2ba587ff3130">
SELECT * FROM viewE WITH (XLOCK) WHERE A < GetUtcDate() </frame>
<frame procname="unknown" line="1" sqlhandle="0x000000000000000000000000000000000000000000000000">
unknown </frame>
</executionStack>
<inputbuf>
(@UICulture nvarchar(5))SELECT * FROM viewE WITH (XLOCK) WHERE A < GetUtcDate() </inputbuf>
</process>
<process id="process6022222" taskpriority="0" logused="161152" waitresource="KEY: 5:72057604035644444 (cd874c2ba438)" waittime="1370" ownerId="27202248438" transactionguid="0x8de5ccd6eeef67469c6234af59e44ca5" transactionname="DTCXact" lasttranstarted="2015-09-14T16:32:34.767" XDES="0x4aa0bf950" lockMode="RangeI-N" schedulerid="14" kpid="6636" status="suspended" spid="329" sbid="0" ecid="0" priority="0" trancount="2" lastbatchstarted="2015-09-14T16:32:37.300" lastbatchcompleted="2015-09-14T16:32:37.300" clientapp="x" hostname="x" hostpid="14536" loginname="x" isolationlevel="read uncommitted (1)" xactid="27202248438" currentdb="5" lockTimeout="4294967295" clientoption1="671088672" clientoption2="128056">
<executionStack>
<frame procname="adhoc" line="1" stmtstart="936" sqlhandle="0x020000004853462f09790a4ddedc0d574c2afa539aef1c0e">
INSERT INTO [E] ([a], [b], [c],...) VALUES (@aDate, @bDate, @c, ...)
</frame>
<frame procname="unknown" line="1" sqlhandle="0x000000000000000000000000000000000000000000000000">
unknown </frame>
</executionStack>
<inputbuf>INSERT INTO [E] ([a], [b], [c],...) VALUES (@aDate, @bDate, @c, ...)
</inputbuf>
</process>
</process-list>
<resource-list>
<keylock hobtid="72057604035644444" dbid="5" objectname="db.dbo.E" indexname="IX_index1" id="lock258b6dc80" mode="X" associatedObjectId="72057604035644444">
<owner-list>
<owner id="process6022222" mode="X"/>
</owner-list>
<waiter-list>
<waiter id="process222222221" mode="RangeX-X" requestType="wait"/>
</waiter-list>
</keylock>
<keylock hobtid="72057604035644444" dbid="5" objectname="db.dbo.E" indexname="IX_index1" id="lock7b145c400" mode="RangeX-X" associatedObjectId="72057604035644444">
<owner-list>
<owner id="process222222221" mode="RangeX-X"/>
</owner-list>
<waiter-list>
<waiter id="process6022222" mode="RangeI-N" requestType="wait"/>
</waiter-list>
</keylock>
</resource-list>
</deadlock>
</deadlock-list>
Run Code Online (Sandbox Code Playgroud)
据我了解,我正在查看一个 KEYLOCK 死锁,该死锁基本上是由未覆盖的索引查询引起的,该查询使用非聚集索引和聚集索引来收集所需的值,对吗?
我的问题:
Pau*_*ite 15
据我了解,我正在查看一个 KEYLOCK 死锁,该死锁基本上是由未覆盖的索引查询引起的,该查询使用非聚集索引和聚集索引来收集所需的值,对吗?
基本上,是的。读操作(选择)首先访问非聚集索引,然后是聚集索引(查找)。写操作(插入)首先访问聚集索引,然后是非聚集索引。以不同的顺序访问相同的资源并持有不兼容的锁可能会导致死锁。
大幅减少行数会有帮助吗?
它可能会,因为较少的资源被锁定,该操作将趋向于更快地完成。如果它确实有帮助,它可能会减少死锁,但很可能不会消除它们(但请继续阅读)。
有什么好的理由我只是不知道 SELECT 是用 XLOCK 执行的吗?
并不真地。像这样的锁定提示通常是由对隔离、锁定和死锁的工作原理没有完全了解的人引入的,他们拼命地试图减少或消除问题。
没有 XLOCK 也会发生死锁吗?
不,如果选择实际上以读取未提交隔离运行,因为不会以不同的顺序获取(和持有)不兼容的锁。
是的,如果使用锁定隔离级别,并且以不一致的顺序获取和持有不兼容的锁,例如在非集群上共享(S),然后在读取时集群上的 S。在这种情况下,死锁的可能性取决于使用了多少个锁,以及它们被持有的时间。
真正突出的事情(在审查中)是 select 事务在可序列化隔离下运行。这可能是由您的框架设置的,或者是由于使用了 DTC(分布式事务协调器) - 请参阅死锁图中的 transactionname="DTCXact"。您应该调查造成这种情况的原因,并在可能的情况下进行更改。
如果没有升级到可序列化,假设XLOCK提示被删除,这种死锁很可能不会发生。也就是说,您将在读取未提交隔离下阅读,这几乎没有一致性保证。
如果您的应用程序和SQL Server的代码可以容忍读取行版本,更改为读提交快照隔离(RCSI)或快照隔离(SI)的读取也将避免死锁(XLOCK删除!),而呈现出一致的,点式- 提交数据的时间视图。当然,这也假设您可以避免可序列化的隔离。
最终,XLOCK提示是适得其反,但你真的需要考虑对使用串行隔离级别的原因。这trancount = 2也很有趣 - 也许您无意中将事务嵌套在这里。还有什么要检查的。
| 归档时间: |
|
| 查看次数: |
11332 次 |
| 最近记录: |