找出出现次数最多的时段

时间:2017-06-16 20:35:07

标签: mysql sql

以这种形式给出一个表“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   |

实际上,有数百万个事件要处理。

我的解决方案是:

  • 创建一个临时表,其中事件以分钟为单位分组
  • LEFT将其与每个时期之间的事件联系起来

请参阅http://sqlfiddle.com/#!9/8546a/1

但表现很糟糕......

有更好的方法吗?

2 个答案:

答案 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表中,这将消除查询执行期间的转换需求。