死锁使用自引用外键

时间:2011-05-05 13:46:15

标签: sql locking foreign-keys deadlock indexing

使用SQL Server 2005:我有一个具有自引用外键的表。

更新&此表上的插入同时发生,但仅限于以下条件:

  • 更新发生在第1天
  • 更新是针对将由insert语句的外键引用的记录

在更新期间,在主键上创建X锁,该主键是表的聚簇索引。我尝试了几种方法来防止这种情况发生,例如:

  • 我尝试更改事务隔离级别
  • 提供表提示,即WITH(nolock)
  • 我尝试在表的主键上创建一个非聚集索引,以便可以使用它而不是聚簇索引。

外键需要存在,因此删除它不是一种选择。关于如何阻止锁定停止插入或允许插入物在锁定周围工作的任何建议都会非常有用。

感谢。

4 个答案:

答案 0 :(得分:0)

您是否尝试通过BEGIN TRANSACTION和COMMIT分离UPDATE和INSERT事务。这样你就可以远离死锁。

类似的东西;

BEGIN TRANSACTION insert
  <INSERT SQL>
  COMMIT TRANSACTION insert
  BEGIN TRANSACTION update
     <UPDATE SQL>
  COMMIT TRANSACTION update
END

答案 1 :(得分:0)

如果发现某条记录符合UPDATE的条件,则会在其上放置X锁定(或其页面等,具体取决于引擎选择的锁定粒度)。

这可以防止S锁定在受影响的资源上,这是检索其值所必需的。

由于将值插入子表需要针对父表进行检查,因此INSERT语句必须等到UPDATE事务提交或回滚。

如果您使PRIMARY KEY非群集,UPDATE不应该影响它(除非您正在更新PRIMARY KEY本身,在正常情况下您不应该这样做),所以{ {1}}会成功。

以下命令对我有用:

交易1:

INSERT

交易2:

CREATE TABLE parent (id INT NOT NULL PRIMARY KEY NONCLUSTERED, value INT NOT NULL, parentId INT REFERENCES parent)

INSERT
INTO    parent
VALUES  (1, 1, NULL)

BEGIN TRANSACTION
UPDATE  parent
SET     value = 2
WHERE   id = 1

答案 2 :(得分:0)

请提供DDL以及我无法重现的UPDATE / INSERT声明。

CREATE TABLE T
(
id int identity(1,1) primary key,
refid int references T(id),
filler char(10)
)

INSERT INTO T (refid)
select number 
FROM master..spt_values where number between 1 and 2248

连接1

BEGIN TRAN
UPDATE T SET filler = 'A' WHERE id=500  

连接2

BEGIN TRAN
INSERT INTO T (refid) VALUES (500) /*Blocked - No deadlock*/

答案 3 :(得分:0)

我最近碰到了同样的问题。正如this post中提到的,我的解决方案是在自引用列(而不是pk)上添加索引。在那之后,死锁完全消失了。