考虑下表:
CREATE TABLE `multiqueue` (
`ID` BIGINT(20) NOT NULL AUTO_INCREMENT,
`CustomerID` BIGINT(20) NOT NULL,
`Volume` INT(11) NOT NULL,
`Content` MEDIUMTEXT NOT NULL COLLATE 'utf8mb4_unicode_ci',
`PublishedTS` DATETIME NULL DEFAULT NULL,
PRIMARY KEY (`ID`) USING BTREE
)
COLLATE='utf8mb4_unicode_ci'
ENGINE=InnoDB
;
该表用作多队列,这意味着它聚合来自多个客户(用 表示CustomerID
)的请求队列,每个请求都有一定Volume
的工作。
如何编写一个查询,N
从表中选择最上面的行,交错来自不同客户的行?
如果客户 1 发送 100 个请求,每个请求量为 1000,然后客户 2 发送 20 个请求,每个请求量为 300,我希望在我的程序忙于处理请求时,查询不会迫使任何客户饿死响应另一个客户的。第一次取客户 1 的 1 个请求和客户 2 的 3-4 个请求,处理它们,然后再接受客户 1 的 1 个请求和客户 2 的 3-4 个请求,以此类推。
到目前为止我已经尝试过:
SET @runtot := 0;
SELECT q1.id1, q1.customerId1, q1.volume1, q1.content1, (@runtot := @runtot + q1.volume1) AS rt
FROM (
SELECT ID AS id1, CustomerID AS customerId1, Content AS content1
FROM multiqueue
ORDER BY id1
) AS q1
WHERE @runtot < 2000
如此处所述,上面的代码通过所选行中某些字段的运行总计来限制所选项目的数量。在上面的场景中,当上面的查询正在使用时,客户 2 会饿死。
使用的数据库是 MariaDB(版本 10.4.13,但如果需要我可以升级到最新版本),不过 MySQL 的解决方案也应该可以工作。
对于最新版本,您可以使用窗口函数:
编辑:
如果您希望每个客户至少有 1 行,您可以添加另一个
ROW_NUMBER()
枚举结果的窗口函数,并在您的选择中使用它:“不用排队,就做吧。” 也就是说,不要费心将请求放入队列中,分拆一个进程来完成任务。这让操作系统来共享资源。并且避免了当您尝试将 MySQL 用作队列时可能发生的一些麻烦。