开发者

Deadlock Using self-referential foreign key

开发者 https://www.devze.com 2023-03-02 21:04 出处:网络
Using SQL server 2005: I\'ve got a table which has a self referencing foreign key. A deadlock occurs when an update & an insert on this table occur simultaneously but only in the following condit

Using SQL server 2005: I've got a table which has a self referencing foreign key.

A deadlock occurs when an update & an insert on this table occur simultaneously but only in the following conditions:

  • the update occurs 1st
  • the update is against the record which will be ref开发者_开发知识库erenced by the foreign key of the insert statement

During the update an X lock is created on the primary key which is the clustered index of the table. I have tried several things to try and prevent this happening such as:

  • I've tried changing transaction isolation levels
  • providing table hints ie WITH(nolock)
  • I tried creating a non-clustered index on the primary key of the table so that this could be used instead of the clustered one.

The foreign key needs to be there so removing it is not an option. Any suggestions on how I can either prevent the lock which stops the insert, or allow the insert to work around the lock would be very helpful.

Thanks.


Have you tried separating your UPDATE and INSERT transactions by BEGIN TRANSACTION and COMMIT. That way you stay away from deadlocks.

Something like that;

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


Please provide DDL and your UPDATE / INSERT statements I can't reproduce this.

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

Connection 1

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

Connection 2

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


When a record is found eligible for UPDATE, an X lock is placed on it (or its page etc., depending on the locking granularity chosen by the engine).

This prevents placing the S lock on the resource affected which is required to retrieve its value.

Since inserting a value into the child table requires checking it against the parent table, the INSERT statement will have to wait until the UPDATE transaction commits or rolls back.

If you make the PRIMARY KEY non-clustered, UPDATE should not affect it (unless you are updating the PRIMARY KEY itself which you should not do in normal circumstances), so the INSERT will succeed.

The commands below work for me:

Transaction 1:

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

Transaction 2:

INSERT
INTO    parent
VALUES  (2, 1, 1)


I recently ran into this exact same problem. As mentioned in this post, the solution for me was to simply add an index on the self-referencing column (not the pk). After that, the deadlocks completely disappeared.

0

精彩评论

暂无评论...
验证码 换一张
取 消

关注公众号