我有一个T-SQL查询,它将工作队列中的下一个项ID返回给任务工作者。在返回之前,查询使用workerID更新行,因此不应多次分配。此查询适用于大多数情况,但最近我们发现将相同的唯一项ID返回给多个任务工作者。
一些可能有用的环境信息:总体积不到100个任务工作者。任务获取很少比每5秒更频繁地发生,并且每个工作单位平均10秒,因此同一工人每分钟进行6-10次采集。该表有大约100万条记录,整个查询执行时间不到1秒。表PK是带有聚簇索引的itemID。
我无法在生产中运行它的用户之外复制问题,因此我怀疑它与运行时相关。这给我留下了几个问题:
在C中的更新将其从A中的查询中排除之前,几乎同时启动的多个查询是否可能产生相同的结果?
如果是,可以做些什么呢?如果没有,我应该在哪里看下一个?
以下是查询内容的摘要。 A和B看起来多余,但这是我支持的遗留代码。在实施变更之前我需要一个计划。
/*
Definitions
@workerID INT -- the task worker
,@workQueueID INT -- different work queues
,@itemID INT -- the unique task item
*/
/* Temp table to store next item */
DECLARE @temp TABLE(
itemID INT,
workQueueID INT,
rownum INT
)
/* A) Select row 1 into @temp */
INSERT INTO @temp
SELECT *
FROM
(
SELECT A.itemID,
A.workQueueID,
ROW_NUMBER()
OVER(
PARTITION BY a.workQueueID
ORDER BY a.taskPriority DESC
) 'RowNum'
FROM workQueue a
WHERE workerID IS NULL
AND workQueueID = @workQueueID
)
WHERE RowNum = 1
/* B) Set @itemID and @workQueueID */
SELECT TOP 1 @itemID = Q.itemID,
@workQueueID = Q.workQueueID
FROM @temp T
JOIN workQueue Q
ON Q.itemID = T.itemID
WHERE Q.workerID IS NULL
ORDER BY Q.workQueueID
/* C) Assign workerID */
UPDATE workQueue
SET workerID = @workerID,
StartTime = GETDATE()
WHERE itemID = @itemID
/* D) Return xml string to task worker */
SELECT @itemID [itemID]
FOR XML AUTO, ELEMENTS, TYPE
答案 0 :(得分:0)
A)一种解决方案是在事务中包装所有内容,并在第一次访问UPDLOCK
表时使用workQueue
提示。
B)另一种解决方案是在您选择项目的同一语句中进行更新,例如:
/*
CREATE TABLE workQueue (
workQueueID INT NOT NULL,
itemID INT UNIQUE,
workerID INT NULL,
StartTime DATETIME NULL,
taskPriority INT NOT NULL
)
CREATE INDEX IX_workQueue ON dbo.workQueue (taskPriority DESC) WHERE workerID IS NULL
INSERT INTO workQueue VALUES (1,1,NULL,NULL,2)
INSERT INTO workQueue VALUES (1,2,NULL,NULL,1)
INSERT INTO workQueue VALUES (2,3,NULL,NULL,4)
INSERT INTO workQueue VALUES (2,4,NULL,NULL,3)
*/
DECLARE @workerID INT=7 -- the task worker
,@workQueueID INT=1 -- different work queues
,@itemID INT -- the unique task item
UPDATE x
SET workerID = @workerID, StartTime = GETDATE(),
@itemID=itemID,
FROM (
SELECT TOP 1 A.*
FROM workQueue a
WHERE workerID IS NULL
AND workQueueID=@workQueueID
ORDER BY a.taskPriority DESC
) x
SELECT @itemID [itemID]
FOR XML PATH, ELEMENTS, TYPE
我不清楚工人如何与不同的工作队列相关:任何工人都可以从任何工作队列中取出物品?如果每个工作队列中有一个项目(但具有不同的优先级),是否有任何规则选择哪个项目?由于代码中的PARTITION BY
,似乎没有规则(可以选择任何项目)。