工作了SQL查询优先级队列表
-
19-08-2019 - |
题
我实现小型队列来处理该方法到达第一运行。我使用的数据库中的表来做到这一点。下面是表的结构(我嘲笑它在SQLite的):
"id" INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL ,
"identifier" VARCHAR NOT NULL ,
"priority_number" INTEGER DEFAULT 15,
"timestamp" DATETIME DEFAULT CURRENT_TIMESTAMP,
"description" VARCHAR
我试图写SQL给我这些过程可以运行下的行。下面是一些示例数据:
id identifier priority_number timestamp description
1 test1 15 2009-01-20 17:14:49 NULL
2 test2 15 2009-01-20 17:14:56 NULL
3 test3 10 2009-01-20 17:15:03 NULL
4 test4 15 2009-01-20 17:15:08 NULL
5 test5 15 2009-01-20 17:32:23 NULL
6 test6 14 2009-01-20 17:32:30 NULL
7 test7 7 2009-01-20 17:32:38 NULL
8 test8 20 2009-01-20 17:32:57 NULL
9 test9 7 2009-01-21 13:47:30 NULL
10 test10 15 2009-01-21 13:50:52 NULL
如果我用这个SQL,我可以以适当的顺序数据:
select * from queue_manager order by priority_number, timestamp;
这会给我在顶部最低优先级数(最重要的)的项目,在这些优先号码,最早到顶部的队列(由时间戳)。
我可以运行此查询,并且只取第一行,但我宁愿做一个SQL查询,这将使我的过程,是在队列的顶部的一排(在本例以上数据与ID = 7)的行。
我试着做自我连接和子查询,但我必须有一个心理障碍 - 我似乎无法得到它的权利。
提前感谢!
修改强>
我忘了提,我找了一个独立于数据库查询。我SQLite中嘲笑他了,但我会在DB2或Oracle实现一个很好的可能性。我曾想过使用“限制1”式的经营者本人的查询,但那是不同的数据库引擎之间的不同。
解决方案
请参阅如果这个工程:
select * from queue_manager where priority_number =
(select min(priority_number) from queue_manager) and
timestamp = (select min(timestamp)
from queue_manager qm2
where qm2.priority_number = queue_manager.priority_number)
其他提示
select * from queue_manager order by priority_number, timestamp LIMIT 1;
对于这种所谓的“数据库独立性”,这是大多数现实世界任务的神话。作为一项规则,你甚至不能在创建数据库无关的方式架构。
如果您希望它是“并发安全”的东西像InnoDB的事:
1)添加 'IN_PROGRESS' 字段。
2)关闭自动提交
3)SELECT * FROM queue_manager其中IN_PROGRESS = 0 ORDER BY priority_number,时间戳LIMIT 1 FOR UDPATE;
4)UPDATE SET queue_manager IN_PROGRESS = 1其中id = X;
5)COMMIT
6)做的工作。然后删除该行的时候做满意。有一个'主进程的句柄/重新委派/清理旧“IN_PROGRESS”的工作。
要做到这一点,最好的方法是数据库依赖性的;这是一个有不同的检索特效为不同的目标的DBMS与所有游标或其他结构的开销要简单得多的事情。
按行的数量有限,不同的是在SQL的不同口味做,所以这取决于你正在使用可能会有办法做到这一点内置。例如,在MS SQL服务器:
SELECT TOP 1
identifier,
priority_number,
timestamp,
description
FROM
dbo.Queue_Manager
ORDER BY
priority_number,
timestamp
要在ANSI兼容的SQL做到这一点,下面的方法应该工作:
SELECT
QM1.identifier,
QM1.priority_number,
QM1.timestamp,
QM1.description
FROM
Queue_Manager QM1
LEFT OUTER JOIN Queue_Manager QM2 ON
QM2.priority_number < QM1.priority_number OR
(QM2.priority_number = QM1.priority_number AND QM2.timestamp < QM1.timestamp)
/* If you're concerned that there might be an exact match by priority_number
and timestamp then you might want to add a bit more to the join */
WHERE
QM2.identifier IS NULL
或者你可以尝试:
SELECT
QM1.identifier,
QM1.priority_number,
QM1.timestamp,
QM1.description
FROM
Queue_Manager QM1
INNER JOIN
(
SELECT
priority_number
MIN(timestamp) AS timestamp,
FROM
Queue_Manager
WHERE
priority_number =
(
SELECT
MIN(priority_number)
FROM
Queue_Manager
)
GROUP BY
priority_number
) SQ1 ON
SQ1.priority_number = QM1.priority_number AND
SQ1.timestamp = QM1.timestamp
这两种方法都占两个priority_number和时间戳精确匹配,所以,如果你认为这是可能的(甚至如果你没有),你需要添加一两行使用标识符走一个多层次或别的事情,保证唯一性。或者只写你的前端处理取回两行的偶然情况下(也许只是忽略第二 - 通过下一次你会得到它)。
测试每个方法,看看哪对你的作品好。
另外,如何大你期望的队列中得到什么?这可能是合理的,只是你的ORDER BY查询并且只前端获取第一条记录。
这部分和选择,为您提供最变种合适的相容性。也许使用游标是唯一或多或少普遍兼容的方式,但有一定的性能损失,可能不能使它值得(配置文件!)。
关系数据库是不是很大,在管理队列。
尝试在Windows世界看MSMQ,ActiveMQ的在Java世界或WebSphere MQ的在商业世界。
这些产品做一件事,管理队列,但他们做得很好。