4

次のようなテーブルがあるとします。

CREATE TABLE foo (
    gid BIGINT PRIMARY KEY,
    starttime BIGINT,
    endtime BIGINT
);

このテーブルには、一連のゲームの開始時刻と終了時刻が(「エポックからの秒数」形式で)格納されます。ここで、特定の瞬間にいくつのゲームが実行されているかを知りたいです。これは自然なクエリです:

SET @t = UNIX_TIMESTAMP('2012-07-12 12:00:00');
SELECT COUNT(f.gid) FROM foo f WHERE @t BETWEEN f.starttime AND f.endtime;

厄介なのは、これを5分ごとに行う必要があることです(各ゲームは数分しか続かず、1時間ごとに数千あります)。おそらく6か月間です。興味のある日付範囲をループして、5分間隔で@tを生成する手順があります。問題は、クエリが遅すぎることです。私は現在、次のように、インデックスを付けた別のテーブルにすべての@tを格納しています。

CREATE TABLE bar (
    interval BIGINT PRIMARY KEY
);

したがって、私が今持っているクエリは次のとおりです。

SELECT b.interval, COUNT(f.gid)
FROM bar b LEFT JOIN foo f
    ON b.interval BETWEEN f.starttime AND f.endtime
GROUP BY b.interval;

これは遅すぎるので、テーブル「foo」のインデックス作成の量は役に立たないようです。これはおそらく標準的なクエリパターンの標準的な問題であると私は感じているので、ここで助けていただければ幸いです。

4

2 に答える 2

1

インターバルが経過したら、実行中のゲーム数を再度計算する必要はないと思います。

では、別の列を に追加してみませんbarか?

CREATE TABLE bar (
    interval BIGINT PRIMARY KEY,
    runningGames INT)

そうすれば、スケジュールされたタスクを 5 分ごとに実行するように設定するだけで済みます

INSERT into bar 
SELECT  UNIX_TIMESTAMP(NOW()),
        COUNT(*) 
FROM    foo
WHERE   endtime is null

6 か月分のデータを何度も再作成する必要はありません。

于 2012-07-13T11:02:52.827 に答える
0

残念ながら、これはウィンドウ/分析関数を使用するとはるかに簡単です。

mysql では、次の戦略を使用して問題を解決できます。

開始時間の一時テーブルを作成します。開始一時テーブルには、行番号を追跡する自動インクリメント ID があります。次に、開始時刻を順番に挿入します。

終了時刻の一時テーブルを作成します。最後の一時テーブルには、行番号を追跡する自動インクリメント ID があります。次に、終了時刻を順番に挿入します。

これらのテーブルには、時間の始まりからの開始と停止の累積数があります。

各 5 分の間隔に少なくとも 1 つの開始と停止があると仮定すると、次を使用してこのテーブルにクエリを実行できます。

select t.time, s.seqnum - e.seqnum
from (select <cast datetime to 5-minute interval> as time, seqnum
      from starts
     ) s full outer join
     (select <cast datetime to 5-minute interval> as time, seqnum
      from ends
     ) e
     on s.time = e.time

これは、インターバルごとに、スタートの累積数を取り、ストップの累積数を差し引いています。mysql で最も近い 5 分に時間を切り捨てる/丸める方法は、私よりもよく知っていると思います。

于 2012-07-13T13:48:12.463 に答える