0

我正在为我们的内部生产制定调度程序。问题的故事是这样的:我们有传入的“工作”,它们被发送到各个站点的“机器”。我们将作业列表存储在 mysql 数据库中。我想为生产协调员创建一个界面:负责将作业放到正确的机器上的人 - 这将包括传入作业的列表,以及代表该机器的作业队列的每台机器的列表。

我们需要能够执行的一些操作: - 重新排序列表而不需要大量写入 sql DB - 例如将作业放在队列顶部而不是队列末尾的机器上,剩下的que 的正确更新(一连串的重新编号是我试图避免的)。

我担心的是可扩展性,如果我们有 100000 个工作,或者我们是否大量增加机器的数量。

我们已经考虑过并且仍在争论的一些事情:创建具有以下结构的表:jobkey、machineid、status、queposition。queposition 的约束相对于 machineid 是唯一的。这对任何数量的机器都有好处,但是快速更新 que 需要在所有 db 中搜索每个机器 ID,并且重新排序不会那么干净。另一个想法是有一个 prekey 和 postkey 字段来模拟一个链表,其中 prekey 是最后一个 que 条目的表键,而 post 将指向下一个。这将解决一些问题,但解决问题可以归结为显示 que。

这些似乎都不能完全解决问题。

这似乎是一个足够普遍的问题,我确信 que 有一个很好的解决方案 - 并且修改所述列表的顺序而不会发生冲突。在 javascript、php 和 mysql 中工作。

4

2 回答 2

0

所以你有 100000 个工作,你担心更新工作需要做多少工作?100000真的不多。一个标准的 mysql 数据库应该能够非常快地处理这些查询。这让数据库使用所有相关项目。

在 mysql fiddle 上创建模式需要 187 毫秒。

在我的本地开发机器上运行它,插入 100.000 个虚拟行需要 650 毫秒。排序顺序的实际更新?不可测量。

17:39:40 CREATE TABLE test( idINT(11) NOT NULL AUTO_INCREMENT, machine_idINT NULL, job_idINT NULL, sort_orderINT NULL, PRIMARY KEY ( id),INDEX machine( machine_idASC, sort_orderASC)) 0 行受影响 0.016 秒

17:39:40 插入test(machine_id, job_id, sort_order) 值 (1,1,1) 1 行受影响 0.000 秒

17:39:40 插入test(machine_id, job_id, sort_order) select t.machine_id, t.job_id, t.sort_order from testt 1 行受影响的记录:1 重复:0 警告:0 0.000 秒

17:39:40 插入test(machine_id, job_id, sort_order) select t.machine_id, t.job_id, t.sort_order from testt, testt2, testt3, testt4 16 行受影响记录:16 重复:0 警告:0 0.000秒

17:39:40 插入test(machine_id, job_id, sort_order) select t.machine_id, t.job_id, t.sort_order from testt, testt2, testt3, testt4 104976 行受影响记录:104976 重复:0 警告:0 0.657秒

17:39:41 更新测试集 machine_id = 50 其中 id > 49555 和 id < 49999 443 行受影响 匹配行:443 更改:443 警告:0 0.000 秒

17:39:41 更新测试 MAIN INNER JOIN (SELECT id, machine_id, @rowNumber := @rowNumber + 10 AS rn FROM test , (SELECT @rowNumber := 0) var where machine_id=50 ORDER BY sort_order ASC ) AS t ON MAIN.id = t.id SET MAIN.sort_order = t.rn 其中 MAIN.machine_id = 50 443 行受影响的行匹配:443 更改:443 警告:0 0.000 秒

我的建议是:确保你的索引没问题,让数据库来做繁重的工作。在您的代码中进行一些测试,以最大限度地利用数据库,使数据库服务器处于压力之下。让它在 5 分钟内完成一天的工作。我敢打赌,它会坚持下去。

确保您的 sort_order 在排序之间总是有 10 步的差异。这样一来,您总是可以在必须使用相关条目之前插入“9”个工作。还有一个轻量级的关系表,它将作业链接到机器,只有排序顺序作为额外数据,并且可能添加了一个主键,以便能够轻松地直接更新作业关系。

以这个演示数据库为例:http ://sqlfiddle.com/#!9/3cf11e/1

CREATE TABLE `test` (
  `id` INT(11) NOT NULL AUTO_INCREMENT,
  `machine_id` INT NULL,
  `job_id` INT NULL,
  `sort_order` INT NULL,
  PRIMARY KEY (`id`),INDEX `machine` (`machine_id` ASC, `sort_order` ASC));
  
insert into `test` (machine_id, job_id, sort_order) values (1,1,1);
insert into `test` (machine_id, job_id, sort_order) select t.machine_id, t.job_id, t.sort_order from `test` t;
insert into `test` (machine_id, job_id, sort_order) select t.machine_id, t.job_id, t.sort_order from `test` t, `test` t2, `test` t3, `test` t4; 
insert into `test` (machine_id, job_id, sort_order) select t.machine_id, t.job_id, t.sort_order from `test` t, `test` t2, `test` t3, `test` t4; 
update test set machine_id = 50 where id > 49555 and id < 49999;


UPDATE 
test MAIN 
INNER JOIN 
(
    SELECT 
        id,
        machine_id,
        @rowNumber := @rowNumber + 10 AS rn
    FROM test , (SELECT @rowNumber := 0) var
  where machine_id=50
    ORDER BY sort_order ASC
) AS t
ON MAIN.id = t.id
SET MAIN.sort_order = t.rn
where MAIN.machine_id = 50;

select * from test where machine_id = 50;

记录数:443;执行时间:11ms

于 2019-12-04T16:42:48.593 回答
0

拥有“队列位置”列的想法对我来说很有意义。(继续索引该列并结合机器 ID。)然后,在查询数据库时,ORDER BY ... DESC该队列位置列和其他一些有意义的列……比如说时间戳。

队列位置值不必是连续的,也不必是唯一的,一个简单的select.. MAX()查询可以告诉您当前存在的最高值(对于特定机器)。只需更新您想要顶到顶部的一行。

如果您确实预计会有少量重新排序,那么另一个简单的技巧是借鉴旧的 BASIC 编程时代并使用递增的队列位置值,例如10. 如果您希望自己的定位相当准确,这将为您提供可以使用的未使用值。(正如我所说,这些值不必是连续的,也不必是唯一的。)

于 2019-12-04T16:35:01.933 回答