【发布时间】:2018-02-12 23:07:06
【问题描述】:
我有一个 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
【问题讨论】:
-
包装代码的事务在哪里,它使用什么隔离级别?如果没有事务,您应该期望多个用户以有趣的方式进行交互。提示:使用适当的软件(MySQL、Oracle、DB2 等)和版本标记数据库问题很有帮助,例如
sql-server-2014。语法和功能的差异通常会影响答案。请注意,tsql缩小了选择范围,但没有指定数据库。 -
谢谢 Habo,我用 SQL Server 2014 更新了标签
标签: sql-server tsql sql-server-2014