3

假设我们有这个资源可用性表:

+-----------+-----------------------------------------------------------+
| date      | obvious, the date                                         |
| timeslot  | we have 12 fixed 2-hour timeslots so this will be 1 to 12 |
| r1        | number of resource type 1 available during this timeslot  |
| r2        | same, for resource type 2                                 |
| r3        | same, for resource type 3                                 |
+-----------+-----------------------------------------------------------+

现在,我想查看我可以用来做的所有可用时间段job #43。对于这项工作,我需要 2 个r1单位、1个r2单位和 3 个r3单位。假设这项工作需要一个时间段,我可以使用这个查询:

SELECT `date`, `timeslot` FROM `resource_availability` 
WHERE
  `r1` > '1' AND
  `r2` > '0' AND
  `r3` > '2'
ORDER BY 'date`, `timeslot`;

但是,如果我有另一份工作job #86需要 3 个时间段才能完成并且无法停止重新启动,那么是否可以通过查询获得安全的开始时间?

我目前正在检查while循环中的连续性,但认为可能有可能让查询执行此操作。

如果可能的话,我想知道哪个更快,更有效。对于功效评估,应该注意的是,作为一种位图的该表会非常频繁地更新 - 即,随着每个作业的调度,资源可用性列会得到更新。

此外,很明显,该系统的目的是允许检查假设。如果我的方法不是最优的,还有什么更好的选择?

如果最后一个问题太多,请忽略它,或者在评论中告诉我,我会删除它。

4

1 回答 1

2

唷...我提出了一个想法,可以让你得到你想要的。如果理解起来需要一点时间,请原谅我,但我希望你看到它实际上是一个相当简单的解决方案,可以解决一个中等复杂的问题。

我将构建查询(在 PHP 中)以具有 n 个自连接,其中 n 是作业所需的时隙数。自联接加入下一个连续的时隙,并根据所有时隙中可用的资源对结果进行细化。请注意,您可以将动态创建的 WHERE 子句移动到 JOIN 条件中......我已经看到 MySQL 的版本会以这种方式提高速度。

php代码:

// $r1, $r3, and $r3 are the required resources for this job.

$join_format = 'JOIN timeslots AS %s ON %date = %s.date AND %s.timeslot+1 = %s.timeslot';
$where_format = '(%s.r1 >= '.$r1.' AND %s.r2 >= '.$r2.' AND %s.r3 >= '.$r3.')';

$joins = array();
$wheres = array("block1.date > CURDATE()",
                sprintf($where_format, "block1", "block1", "block1")
                );
$select_list = 'block1.date, block1.timeslot as starting_time, block' . $slots_needed . '.timeslot as ending_time';

for($block = 2; $block <= $slots_needed; $block++) {
  $join_alias = "block" . $block;
  $previous_alias = "block" . ($block-1);
  $joins[] = sprintf($join_format, $join_alias, $previous_alias,$join_alias, $previous_alias, $join_alias);
  $wheres[] = sprintf($where_format, $join_alias, $join_alias, $join_alias);
}

$query_format = 'SELECT %s FROM timeslots as block1 %s WHERE %s GROUP BY block1.date, block1.timeslot ORDER BY block1.date ASC, block1.timeslot ASC';
$joins_string = implode(' ', $joins);
$wheres_string = implode(' AND ', $wheres);
$query = sprintf($query_format, $select_list, $joins_string, $wheres_string);

尽我所能,这应该会产生这样的查询(对于 2 个需要的块,每个需要 1 个资源:

生成的 SQL:

SELECT 
  block1.date,
  block1.timeslot as starting_time, 
  block2.timeslot as ending_time
FROM 
  timeslots AS block1
  JOIN timeslots AS block2
    ON block1.date = block2.date AND block1.timeslot+1 = block2.timeslot
WHERE
  block1.date > CURDATE()
  AND (block1.r1 >= 1 AND block1.r2 >= 1 AND block1.r3 >= 1)
  AND (block2.r1 >= 1 AND block2.r2 >= 1 AND block2.r3 >= 1)
GROUP BY
  block1.date, block1.timeslot
ORDER BY
  block1.date ASC, block1.timeslot ASC

它应该产生如下结果:

预期结果集:

+------------+---------------+-------------+
|    date    | starting_time | ending_time |
+------------+---------------+-------------+
| 2001-01-01 |       1       |      2      |
+------------+---------------+-------------+
| 2001-01-01 |       2       |      3      |
+------------+---------------+-------------+
| 2001-01-01 |       7       |      8      |
+------------+---------------+-------------+
| 2001-01-01 |       8       |      9      |
+------------+---------------+-------------+
| 2001-01-02 |       4       |      5      |
+------------+---------------+-------------+

请注意,如果需要 2 个块,但 3 个可用(连续),则查询返回两个选项(第一个和第二个或第二个和第三个可用时间)。

于 2012-07-11T05:13:14.687 回答