以这种形式给出一个表“events_log”:
| id | started_at | duration |
| 1 | 2017-06-01 09:00:00 | 80 |
| 1 | 2017-06-01 09:01:00 | 40 |
| 1 | 2017-06-01 09:01:23 | 20 |
我想知道大多数事件发生的时间(精确度很高):
|period |count|
| 2017-06-01 09:00:00 | 1 |
| 2017-06-01 09:01:00 | 3 |
实际上,有数百万个事件要处理。
我的解决方案是:
请参阅http://sqlfiddle.com/#!9/8546a/1
但表现很糟糕......
有更好的方法吗?
答案 0 :(得分:0)
我会想group by
,就像这样:
select date_format(started_at, '%Y-%m-%d %h:%i') as yyyymmddhhmi, count(*)
from t
group by yyyymmddhhmi
order by count(*) desc
limit 10;
表现不会很好。
答案 1 :(得分:0)
以下是您的代码的修改版本。它将扫描events_log表两次。一次构建event_starts辅助表时,第二次选择在指定时间间隔内发生的所有事件。另请注意添加索引,这将显着加快执行速度。这也可能是您原始查询速度太慢的原因。
CREATE TABLE events_log (id INT NOT NULL AUTO_INCREMENT PRIMARY KEY,started_at DATETIME,duration INT(11));
INSERT INTO events_log (started_at, duration) VALUES ('2017-06-01 09:00:00', 80);
INSERT INTO events_log (started_at, duration) VALUES ('2017-06-01 09:01:00', 40);
INSERT INTO events_log (started_at, duration) VALUES ('2017-06-01 09:01:23', 20);
CREATE /* TEMPORARY */ TABLE tmp_event_starts AS (
select DISTINCT DATE_ADD(started_at, INTERVAL -SECOND(started_at) SECOND) AS period_start
from events_log
);
create index idx_tmp_event_starts
on tmp_event_starts (period_start);
select period_start, count(*), group_concat(id) from events_log as log
join tmp_event_starts as per
on per.period_start >= DATE_ADD(started_at, INTERVAL -SECOND(started_at) SECOND)
and per.period_start <= DATE_ADD(started_at, INTERVAL -SECOND(started_at)+duration SECOND)
group by period_start
;
如果您在同一分钟内发生了很多事件,并且没有事件没有分钟,那么您可以考虑生成辅助表作为独立于数据的分钟序列。在MySql中,这是一个非常不安的任务,但是在这篇博文Calendar Tables: An Invaluable Database Tool中可以找到一些提示。 它还允许提前生成帮助表,从而显着加快查询本身的执行速度 您还可以考虑将ends_at columnt添加到event_log表中,这将消除查询执行期间的转换需求。