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。このジョブには、r1が 2 ユニット、 r2が 1 ユニット、 r3が 3 ユニット必要です。ジョブに 1 つのタイムスロットが必要であると仮定すると、次のクエリを使用できます。

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

job #86ただし、完了までに 3 つのタイムスロットが必要で、停止して再起動できない別のジョブがある場合、クエリで安全な開始時間を取得することは可能ですか?

現在、ループの連続性をチェックwhileしていますが、クエリでそれを実行できる可能性があると考えました。

それが可能であれば、どちらがより迅速で効率的かを知りたいです。有効性を評価するために、この表は一種のビットマップであり、非常に頻繁に更新されることに注意してください。つまり、ジョブがスケジュールされるたびに、リソースの可用性列が更新されます。

また、このシステムの目的がwhat-ifを調べることであることは明らかです。私のアプローチが最適でない場合、より良い代替手段はありますか?

最後の質問が多すぎる場合は、無視するか、コメントでお知らせください。削除します。

4

1 に答える 1

2

ふぅ…あなたが望むものを手に入れるかもしれないアイデアをまとめました。理解するのに少し時間がかかるかもしれませんが、実際には適度に複雑な問題に対するかなり単純な解決策であることを理解していただければ幸いです。

n個の自己結合を持つように(PHPで)クエリを作成します.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);

私の意図の限りでは、次のようなクエリが生成されるはずです(必要なリソースがそれぞれ1つずつある2つの必要なブロックの場合:

結果の 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 つのブロックが (連続して) 使用可能である場合、クエリ両方のオプション (1 回目と 2 回目、または 2 回目と 3 回目の使用可能時間) を返すことに注意してください。

于 2012-07-11T05:13:14.687 に答える