【发布时间】:2017-09-07 08:33:14
【问题描述】:
简单的问题 - 我在 SQL Server 表中有 300k 个任务,我希望多个进程一个一个地选择它们,处理它们并保存结果。
我不时在挑选和保存方面陷入僵局。
我需要确保两个进程不会选择相同的任务。所以我使用XLOCK,在完成任务后,我将状态从 1-Created 更改为 2-Started,并在处理后更改为 3-Completed。
我的任务 (tblTasksSets) 也被一对一地引用到 tblGeneralSets(请不要问;)),tblGeneralSets 被多对一地引用到 tblContainers。
所以我有两个程序来更新和选择挑选的任务:
DECLARE @SetIds AS TABLE(Id INT)
-- Updating status
;WITH innerTable AS
(
SELECT TOP 1 taskSets.*
FROM tblTasksSets taskSets WITH (XLOCK ROWLOCK)
INNER JOIN tblGeneralSets generalSets WITH(XLOCK ROWLOCK) ON generalSets.TaskSetId = taskSets.Id
WHERE generalSets.ContainerId = @ContainerId
AND taskSets.ParameterSetStatusId = 1 --CREATED
)
UPDATE innerTable
SET ParameterSetStatusId = 2 -- STARTED
OUTPUT INSERTED.Id INTO @SetIds
-- Here are some unrelated updates on log history tables
-- And returning result
SELECT
taskSets.*, containers.*
FROM
tblTasksSets taskSets
INNER JOIN
tblGeneralSets generalSets ON generalSets.TaskSetId = taskSets.Id
INNER JOIN
tblContainers containers ON containers.Id = generalSets.ContainerId
WHERE
taskSets.Id = (SELECT TOP 1 Id FROM @SetIds)
第二个将任务标记为已完成:
UPDATE tblTasksSets
SET
....
WHERE Id = @Id
任何想法为什么我会陷入僵局?我只希望一个进程等待另一个进程完成更新。
System.Data.SqlClient.SqlException (0x80131904):事务(进程 ID 53)与另一个进程在锁资源上死锁,并已被选为死锁牺牲品。重新运行事务。
在测试时,此数据库上没有运行其他查询。每隔几秒可能只有 50 个进程调用这两个存储过程
【问题讨论】:
-
我很确定,当您在此期间运行
sp_lock时,您会看到一个连接在它只想阻塞一个时阻塞了很多行。这将是由于连接和/或缺乏适当的索引。即使不是这种情况,其他连接仍然需要等待以确保当前锁定的行不满足它们的where,因此您的并发性为零。 -
您可能需要
update top (1) ... from ... with (rowlock, holdlock, readpast) where ...。 Thereadpasthint. -
你能发布死锁图吗? sqlmag.com/database-performance-tuning/…
-
GSerg 我在做一些小研究,发现在某些情况下,在这种情况下可能会发生两个查询会选择一个项目,显然更新不是原子操作
-
您是否使用事务,您的隔离级别是多少?
标签: sql sql-server tsql deadlock database-deadlocks