SQL优先级队列操作 - 任何陷阱?

时间:2012-01-12 23:10:45

标签: sql priority-queue

我有一个优先级队列表,可以简单地表示为:

CREATE TABLE test (
  id int PRIMARY KEY,
  priority int,
  status int
)

其中priority是优先级(最低的第一个),status是项目状态(0表示可以检索)。任务是检索具有最高优先级的元素并重置其状态,因此代码就像这样(伪代码):

 try = 0;
 while(try++ < max_tries) {
   result = query("SELECT id FROM test WHERE status=0 ORDER BY priority LIMIT 0,1");
   if(result not empty) {
      /* found a row, try to update */
      result2 = query("UPDATE test SET status=1 WHERE id={result[id]} AND status=0");
      if(affected_rows(result2) > 0) {
         /* if update worked fine, we can use this ID */
         return result[id];
      }
      /* otherwise try again */
 }
 return NULL;

此代码应在任何sql数据库上运行(通过适当的修改,如不同的LIMIT语法)(当前要求是Mysql,Oracle,SQL Server和DB2,但可能更多)。据我所知,所有必需的数据库都支持“受影响的行”API进行更新。这种方法有任何潜在的问题或陷阱吗?应该在上面的语句中使用SELECT ... FOR UPDATE,如果是,为什么?

1 个答案:

答案 0 :(得分:1)

列出的SELECT / UPDATE组合似乎解决了UPDATE的WHERE子句的一致性问题。然而,如果可以接受,我会倾向于存储过程:取决于sql风格,存储过程可以通过原子“UPDATE ... RETURNING id INTO ...”摆脱并发问题。

关于州,如果它们是:

  • 0“可以检索”
  • 1“正在处理中”
  • 2“完成”

然后国家充当锁。如果在状态从0更改为1之后但在实际处理作业之前进程终止,则会出现问题:记录可以保持锁定和未处理,直到清理作业运行。另一种方法是为锁使用单独的时间戳列。然后查询包括过滤器“WHERE now() - timeout&gt; NVL(lockTimestamp,开始时间)”并通过将lockTimestamp设置为now()而不是依赖于设置status = 1来完成锁定。这样,锁可以在合理的等待(超时)之后自动过期,并且该项再次可用以被下一个处理器拾取。无需清理工作。

任何可能无法获得低优先级工作的饥饿机会?

是否需要添加其他订购?如果这些项目都具有相同的优先级,那么首先处理哪些项目(fifo,lifo)是否重要?

我想应该注意的是,如果运行此fetch例程的多个实例,则可以同时处理多个队列项,并且处理顺序不一定是顺序的(process1获取item1,process2获取item2,process2完成item2 ,process1完成item1,...),所以希望没关系,否则锁定需要检查是否还有其他事情正在进行中。

我也没有特别看到需要SELECT ... FOR UPDATE。