SELECT / UPDATE主键上的死锁

时间:2016-01-20 21:09:15

标签: sql-server

我的MS SQL Server 2008数据库中有2个表:

[Person]
-Id
-Name
-Car_Id

[Car]
-Id
-Mileage

现在我运行的服务器进程不断更新不同车辆的里程。

UPDATE Car SET Mileage=1234 WHERE Id=7

然后我有一个客户网格,显示他们的汽车的人和里程。这也会定期更新:

SELECT p.Name, c.Mileage
FROM Person AS p
INNER JOIN Car AS c on p.Car_Id = c.Id

现在经常会导致我的Car表的主键出现死锁: enter image description here

然后SQL服务器中止SELECT查询。据我所知,这与主键上的某种范围锁定有关。一个由UPDATE WHERE子句引起,另一个由INNER JOIN条件引起。

这个假设是否正确?

这种密钥锁定死锁问题的首选解决方案是什么?我假设唯一的方法是重试SELECT或更改事务隔离级别。我不只是想在不完全理解这里的问题的情况下降低隔离级别。

修改

表格的更多细节:

CREATE TABLE [dbo].[Car](
    [Id] [int] IDENTITY(1,1) NOT NULL,
    [Mileage] [int] NULL,
 CONSTRAINT [PK_dbo.Car] PRIMARY KEY CLUSTERED 

CREATE TABLE [dbo].[Person](
    [Id] [int] IDENTITY(1,1) NOT NULL,
    [Name] [nvarchar](max) NULL,
    [Car_Id] [int] NULL,
 CONSTRAINT [PK_dbo.Person] PRIMARY KEY CLUSTERED

ALTER TABLE [dbo].[Person]  WITH CHECK ADD  CONSTRAINT [FK_dbo.Person_dbo.Car_Car_Id] FOREIGN KEY([Car_Id])
REFERENCES [dbo].[Car] ([Id])

ALTER TABLE [dbo].[Person] CHECK CONSTRAINT [FK_dbo.Person_dbo.Car_Car_Id]

CREATE NONCLUSTERED INDEX [IX_Car_Id] ON [dbo].[Person] 
(
    [Car_Id] ASC
)

修改2

刚刚发生的一件事在这里也很重要: 服务器端的事务中总有几个UPDATE,因此并非每个UPDATE都在一个事务中。基本上所有改变的汽车都在一次交易中更新。

3 个答案:

答案 0 :(得分:1)

事实证明,在事务中只运行一个UPDATE可以解决问题。谢谢大家的意见。

答案 1 :(得分:0)

首先,如果更改更新以使其在值已经正确的情况下不更新任何行,是否有帮助?

UPDATE Car SET Mileage=1234 WHERE Id=7 AND Mileage <> 1234;

我认为我不能直接回答你的问题,但试试这个链接Is it possible to force row level locking in SQL Server?

UPDATE Car WITH (ROWLOCK) SET Mileage=1234 WHERE Id=7 AND Mileage <> 1234;

答案 2 :(得分:0)

每当您更新表时,您都会获得对已更新/删除的表行的独占(写入)锁定。 当获得排他锁时,不能获得共享锁(SELECTs所需)。对此最简单的解决方案是回滚事务并让另一个完成并再试一次。我也不会建议你降低隔离度。序列化应该工作正常。 你更新后立即提交?即时提交;更新后的声明可能是您的问题的解决方案,因为在提交后您“回馈”您的独占锁。