在开始和结束时间内以时刻计数记录

时间:2012-07-13 10:20:24

标签: mysql sql

假设我有一个这样的表:

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”上的索引编号似乎没有帮助。我觉得这可能是一个标准问题,可能是一个标准的查询模式,所以在这里会有所帮助。

2 个答案:

答案 0 :(得分: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

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

答案 1 :(得分:0)

唉,使用Windows /分析功能会更容易。

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

创建一个开始时间的临时表。在start临时表中,有一个自动递增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分钟。