dtr*_*roy 7 sql sql-server deadlock sql-server-2005 foreign-keys
我在SQL Server 2005上遇到了多个死锁的问题.这个死锁是在INSERT和SELECT语句之间.
有两张桌子.表1和表2.Table2将Table1的PK(table1_id)作为外键.
table1_id上的索引是群集的.
INSERT一次在table2中插入一行.
SELCET加入了2个表.(这是一个很长的查询,可能需要12秒才能运行)
根据我的理解(和实验),INSERT应该获取table1上的IS锁以检查参照完整性(这不应该导致死锁).但是,在这种情况下,它获得了IX页锁
死锁报告:
<deadlock-list>
<deadlock victim="process968898">
<process-list>
<process id="process8db1f8" taskpriority="0" logused="2424" waitresource="OBJECT: 5:789577851:0 " waittime="12390" ownerId="61831512" transactionname="user_transaction" lasttranstarted="2010-04-16T07:10:13.347" XDES="0x222a8250" lockMode="IX" schedulerid="1" kpid="3764" status="suspended" spid="52" sbid="0" ecid="0" priority="0" transcount="2" lastbatchstarted="2010-04-16T07:10:13.350" lastbatchcompleted="2010-04-16T07:10:13.347" clientapp=".Net SqlClient Data Provider" hostname="VIDEV01-B-ME" hostpid="3040" loginname="DatabaseName" isolationlevel="read uncommitted (1)" xactid="61831512" currentdb="5" lockTimeout="4294967295" clientoption1="671088672" clientoption2="128056">
<executionStack>
<frame procname="DatabaseName.dbo.prcTable2_Insert" line="18" stmtstart="576" stmtend="1148" sqlhandle="0x0300050079e62d06e9307f000b9d00000100000000000000">
INSERT INTO dbo.Table2
(
f1,
table1_id,
f2
)
VALUES
(
@p1,
@p_DocumentVersionID,
@p1
) </frame>
</executionStack>
<inputbuf>
Proc [Database Id = 5 Object Id = 103671417] </inputbuf>
</process>
<process id="process968898" taskpriority="0" logused="0" waitresource="PAGE: 5:1:46510" waittime="7625" ownerId="61831406" transactionname="INSERT" lasttranstarted="2010-04-16T07:10:12.717" XDES="0x418ec00" lockMode="S" schedulerid="2" kpid="1724" status="suspended" spid="53" sbid="0" ecid="0" priority="0" transcount="2" lastbatchstarted="2010-04-16T07:10:12.713" lastbatchcompleted="2010-04-16T07:10:12.713" clientapp=".Net SqlClient Data Provider" hostname="VIDEV01-B-ME" hostpid="3040" loginname="DatabaseName" isolationlevel="read committed (2)" xactid="61831406" currentdb="5" lockTimeout="4294967295" clientoption1="671088672" clientoption2="128056">
<executionStack>
<frame procname="DatabaseName.dbo.prcGetList" line="64" stmtstart="3548" stmtend="11570" sqlhandle="0x03000500dbcec17e8d267f000b9d00000100000000000000">
<!-- XXXXXXXXXXXXXX...SELECT STATEMENT WITH Multiple joins including both Table2 table 1 and .... XXXXXXXXXXXXXXX -->
</frame>
</executionStack>
<inputbuf>
Proc [Database Id = 5 Object Id = 2126630619] </inputbuf>
</process>
</process-list>
<resource-list>
<pagelock fileid="1" pageid="46510" dbid="5" objectname="DatabaseName.dbo.table1" id="lock6236bc0" mode="IX" associatedObjectId="72057594042908672">
<owner-list>
<owner id="process8db1f8" mode="IX"/>
</owner-list>
<waiter-list>
<waiter id="process968898" mode="S" requestType="wait"/>
</waiter-list>
</pagelock>
<objectlock lockPartition="0" objid="789577851" subresource="FULL" dbid="5" objectname="DatabaseName.dbo.Table2" id="lock970a240" mode="S" associatedObjectId="789577851">
<owner-list>
<owner id="process968898" mode="S"/>
</owner-list>
<waiter-list>
<waiter id="process8db1f8" mode="IX" requestType="wait"/>
</waiter-list>
</objectlock>
</resource-list>
</deadlock>
</deadlock-list>
Run Code Online (Sandbox Code Playgroud)
任何人都可以解释为什么INSERT获取IX页锁?
我没有正确阅读死锁报告吗?
顺便说一下,我还没有设法重现这个问题.
谢谢!
编辑:表格创建:
CREATE TABLE [dbo].[Table2] (
[Table2_id] [int] IDENTITY (1, 1) NOT NULL ,
[f1] [int] NULL ,
[Table1_id] [int] NOT NULL ,
[f2] [int] NOT NULL ,
)
ALTER TABLE [dbo].[Table2] ADD
CONSTRAINT [FK_Table2_Table1] FOREIGN KEY
(
[Table1_id]
) REFERENCES [dbo].[Table1] (
[Table1_id]
)
CREATE TABLE [dbo].[Table1] (
[Table1_id] [int] IDENTITY (1, 1) NOT NULL ,
)
ALTER TABLE [dbo].[Table1] WITH NOCHECK ADD
CONSTRAINT [PK_Table1] PRIMARY KEY CLUSTERED
(
[Table1_id]
)
Run Code Online (Sandbox Code Playgroud)
我的意思是'意图'锁定,它们总是与层次结构相关联.因为锁管理器不理解物理结构,所以他不可能尊重分层锁,因此在意图锁中重新创建层次结构.
在您的情况下,INSERT在页面上具有意图锁定.这意味着它还在页面中的一行上获得了X锁定,这是正常行为.它现在尝试获取新的IX锁,因此可能需要在不同的页面中插入一行.这将是插入到具有多个索引的表中的正常行为:第一个IX位于其中一个索引上(可能是聚簇的),第二个IX位于非聚簇索引上.
您说的SELECT在12秒内返回,因此它是一个长查询,在大型数据集上,并且该计划可能选择了高锁粒度,页锁.SELECT在页面上有一个S锁定,INSERT想要IX锁定,并希望在INSERT具有IX锁定的页面上有另一个S锁定.
这是一个微不足道的死锁,应该很容易修复它:确保你的SELECT不需要那些页面S锁.这不是INSERT错误.我不知道SELECt是什么,我无法确定是否是最佳的.根据我的经验,几乎总是像这样的SELECT有足够的,充足的和更多的改进空间(包括SELECT本身或其下面的架构).
但是接受SELECT是最佳的,你最容易获得的监狱卡是开启行版本控制:
ALTER DATABASE <dbname> SET ALLOW_SNAPSHOT_ISOLATION ON;
ALTER DATABASE <dbname> SET READ_COMMITTED_SNAPSHOT ON;
Run Code Online (Sandbox Code Playgroud)
更新:
实际上在第二次阅读时很明显INSERT在不同的表上有锁(除非你修改了XML,看起来在这里和那里进行了手工编辑),所以你对插入行为的解释必定是错误的.INSERT是事务的一部分,而不是至少两次写入,一次在Table1上,一次在Table2上.但这并没有改变很多问题,也没有解决方案.确实,您可以将事务中的两个写入分成单独的事务,但这显然是最糟糕的途径.
在平底船中,我会说 DatabaseName.dbo.prcTable2_Insert 正在事务内执行或显式打开一个事务,并且它(或与打开的事务的连接)已经预先插入到 Table1 中。
| 归档时间: |
|
| 查看次数: |
8948 次 |
| 最近记录: |