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;

复杂的是我需要每五分钟做一次(每场比赛只持续几分钟,我们每小时有几千场),并且可能持续六个月。我确实有循环遍历我感兴趣的日期范围并每隔五分钟生成@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)

这样,您只需将计划任务设置为每五分钟运行一次

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

然后你不应该一次又一次地重新创建六个月的数据

于 2012-07-13T11:02:52.827 回答
0

唉,这使用 Windows/分析功能要容易得多。

在mysql中,可以使用下面的策略来解决问题。

创建一个临时的开始时间表。在启动临时表中,有一个自动递增的 id 来跟踪行号。然后按顺序插入开始时间。

创建一个结束时间的临时表。在最后的临时表中,有一个自动递增的 id 来跟踪行号。然后按顺序插入结束时间。

这些表具有自时间开始以来的累计启动和停止次数。

假设每个 5 分钟间隔至少有一个开始和停止,我们可以使用以下方法查询该表:

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 回答