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