Sql server 如何使用锁定提示,使两个并行查询返回不相交的结果?
我有一个SQL表Sql server 如何使用锁定提示,使两个并行查询返回不相交的结果?,sql-server,database,sql-server-2005,tsql,concurrency,Sql Server,Database,Sql Server 2005,Tsql,Concurrency,我有一个SQL表Tasks,其中包含列Id和State。我需要执行以下操作:查找状态为ReadyForProcessing的任何一个任务,检索其所有列并将其状态设置为Processing。类似于(伪代码): 此查询将从多个数据库客户端并行运行,其思想是,如果两个客户端并行运行查询,它们将获得不同的任务,而不是相同的任务 看起来我需要锁定提示。我读过,但什么都不懂。如何使用锁定提示来解决上述问题 像这样的事情怎么样: UPDATE TOP (1) Tasks SET State = Pr
Tasks
,其中包含列Id
和State
。我需要执行以下操作:查找状态为ReadyForProcessing
的任何一个任务,检索其所有列并将其状态设置为Processing
。类似于(伪代码):
此查询将从多个数据库客户端并行运行,其思想是,如果两个客户端并行运行查询,它们将获得不同的任务,而不是相同的任务
看起来我需要锁定提示。我读过,但什么都不懂。如何使用锁定提示来解决上述问题 像这样的事情怎么样:
UPDATE TOP (1) Tasks
SET State = Processing
OUTPUT INSERTED.RetrievedTaskId
WHERE State = ReadyForProcessing
测试一下:
DECLARE @Tasks table (RetrievedTaskId int, State char(1))
INSERT @Tasks VALUES (1,'P')
INSERT @Tasks VALUES (2,'P')
INSERT @Tasks VALUES (3,'R')
INSERT @Tasks VALUES (4,'R')
UPDATE TOP (1) @Tasks
SET State = 'P'
OUTPUT INSERTED.RetrievedTaskId
WHERE State = 'R'
SELECT * FROM @Tasks
--输出:
我真的,真的不喜欢数据库中的显式锁定,它是各种疯狂错误的来源——数据库的性能可能会下降 我建议按照以下思路重新编写SQL:
begin transaction;
update tasks
set state = processing
where state = readyForProcessing
and ID = (select min(ID) from tasks where state = readyForProcessing);
commit;
这样,您就不需要锁定任何东西,而且因为更新是原子的,所以没有两个进程更新同一条记录的风险。这应该可以做到
BEGIN TRANSACTION
DECLARE @taskId
SELECT TOP (1) @taskid = TaskId FROM Tasks WITH (UPDLOCK, READPAST) WHERE State = 'ReadyForProcessing'
UPDATE Tasks SET State = 'Processing' WHERE TaskId = @taskid
COMMIT TRAN
请参阅和。那么,如何处理作为原子操作检索任务列的需求呢?这正是显式锁定所针对的用例类型。确保不要在SERIALIZABLE下运行它-您可能会遇到转换死锁。在更新之前执行SELECT时,会出现竞争,因此两个线程完全有可能两次更新同一条记录(这可能不是问题,因为他们会将记录更新为相同的值,但我已经看到了这种情况的发生)。处理这种情况的唯一方法是使用显式锁定提示。
begin transaction;
update tasks
set state = processing
where state = readyForProcessing
and ID = (select min(ID) from tasks where state = readyForProcessing);
commit;
BEGIN TRANSACTION
DECLARE @taskId
SELECT TOP (1) @taskid = TaskId FROM Tasks WITH (UPDLOCK, READPAST) WHERE State = 'ReadyForProcessing'
UPDATE Tasks SET State = 'Processing' WHERE TaskId = @taskid
COMMIT TRAN