当结果应该是唯一的时,T-SQL查询会向多个用户返回相同的结果

时间:2018-02-12 23:07:07

标签: sql-server tsql sql-server-2014

我有一个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

1 个答案:

答案 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,似乎没有规则(可以选择任何项目)。