如果表格中有一个工作队列,将由许多不同的工作人员客户定期轮询......阻止每个工作人员获得相同项目的最佳方法是什么?
说出如下表:ItemId,LastAttemptDateTime,AttemptCount和各种项目详情。
给出LastAttemptDateTime的索引并按升序排序,各个客户端正在查询表以获取要处理的项目。
我在MS SQL中使用存储过程来执行此操作......类似于:
CREATE PROCEDURE GetNextQueueItem AS
SET NOCOUNT ON
DECLARE @ItemId INT
UPDATE myqueue SET @ItemId=ItemId, AttemptCount=AttemptCount+1, LastAttemptDateTime=GetDate()
WHERE ItemId=(SELECT TOP 1 ItemId
FROM myqueue
ORDER BY LastAttemptDateTime ASC)
SELECT ItemId, AttemptCount, and various item detail fields
FROM myqueue
WHERE ItemId = @ItemId
我对PostgreSQL还不熟悉,并且想知道是否有其他方法可用。 (TOP 1将更改为LIMIT 1.)
答案 0 :(得分:1)
由于PostgreSQL的序列与标识列分开,并且可以用于其他事物,所以有一个很好的方法可以使用一个序列来设置表上的id,另一个用于获取项目:
查看序列的currval
,如果它高于或等于表格的max
id,则没有等待的项目。
获取nextval
。如果没有匹配id的项目,则循环回1(如果对表的插入失败,则会发生这种情况。)
获取具有匹配ID的行。
这不是剥离这只猫的唯一方法(而不是我与其他数据库一起使用的方式),但有一个优点就是可以轻松写入数据库(只改变序列,而不是表格。
答案 1 :(得分:1)
PostgreSQL等价物可能如下所示:
CREATE OR REPLACE FUNCTION get_next_queue_item()
RETURNS SETOF myqueue AS
$BODY$
BEGIN
RETURN QUERY
UPDATE myqueue
SET attempt_count = attempt_count + 1
,last_attempt_ts = now()
WHERE item_id = (
SELECT item_id
FROM myqueue
ORDER BY last_attempt_ts
LIMIT 1
)
RETURNING myqueue.*;
END;
$BODY$
LANGUAGE plpgsql VOLATILE;
您只需要 1声明即可完成所有操作。 UPDATE
可以使用RETURNING
子句返回同一命令中的更新行。
行的状态是更新后的。如果需要,有办法获得更新前的状态。
无需任何变量。
我将所有标识符更改为小写,这是PostgreSQL中最干净的样式。
我将您的专栏LastAttemptDateTime
重命名为last_attempt_ts
ts ..表示“timestamp”,因为这是Postgres中时间戳/日期时间类型的名称。
正如您所说,LIMIT 1
而不是TOP 1
。
我使用RETURNS SETOF myqueue
作为返回类型
myqueue
是表myqueue
的关联行类型 - 对于每个表或视图,在PostgreSQL中自动创建相同名称的行类型。
此声明允许返回多行,但LIMIT 1
保证它只会返回一行。
此返回类型允许RETURN QUERY直接返回结果行,而无需任何中间步骤。快速,干净。
实际上,你根本不需要一个plpgsql函数。您可以使用简单SQL语句:
来完成此操作UPDATE myqueue
SET attempt_count = attempt_count + 1
,last_attempt_ts = now()
WHERE item_id = (
SELECT item_id
FROM myqueue
ORDER BY last_attempt_ts
LIMIT 1
)
RETURNING myqueue.*;