【问题标题】:How to select most dense 1 min in Oracle如何在Oracle中选择最密集的1分钟
【发布时间】:2016-06-19 16:15:35
【问题描述】:

我有一个带有时间戳列tmstmp 的表,该表包含某些事件的日志。我需要找出在 1 分钟间隔内发生的最大事件数。

请仔细阅读!我确实想要提取时间戳分钟分数并像这样求和:

select count(*), TO_CHAR(tmstmp,'MI') 
   from log_table 
     group by TO_CHAR(tmstmp,'MI')
     order by TO_CHAR(tmstmp,'MI');

它需要先取第一条记录,然后向前看,直到它从第一条开始1分钟内选择所有记录并求和记录数,然后取第二条并做同样的事情......

结果必须有一个(总和,起始时间戳)的记录集。

有人在某处有sn-p代码并愿意分享吗?

【问题讨论】:

标签: sql oracle oracle11g


【解决方案1】:

带有逻辑窗口的分析功能可以直接提供这些信息:

select l.tmstmp,
count(*) over (order by tmstmp range between current row and interval '59.999999' second following) cnt
from log_table l
order by 1
;

TMSTMP                             CNT
--------------------------- ----------
01.01.16 00:00:00,000000000          4 
01.01.16 00:00:10,000000000          4 
01.01.16 00:00:15,000000000          3 
01.01.16 00:00:20,000000000          2 
01.01.16 00:01:00,000000000          3 
01.01.16 00:01:40,000000000          2 
01.01.16 00:01:50,000000000          1

请根据您的精度调整间隔长度。它必须是低于 1 分钟的最大可能值。

要获得最大分钟数,请使用子查询(不要忘记您可能会收到一条以上的记录 - 使用 MAX 计数):

with tst as (
select l.tmstmp,
count(*) over (order by tmstmp range between current row and interval '59.999999' second following) cnt
from log_table l)
select * from tst where cnt = (select max(cnt) from tst);

TMSTMP                             CNT
--------------------------- ----------
01.01.16 00:00:00,000000000          4 
01.01.16 00:00:10,000000000          4 

【讨论】:

  • 虽然 @CarloCe 提供了有趣的解决方案并且速度很快,但这个解决方案在我们的 prod exadata 上运行速度确实快了 20 倍。
【解决方案2】:

我认为您可以使用SELECT 语句中的子查询来实现您的目标,如下所示:

SELECT tmstmp, (
    SELECT COUNT(*) 
    FROM log_table t2 
    WHERE t2.tmstmp >= t.tmstmp AND t2.tmstmp < t.tmstmp + 1 / (24*60)
) AS events
FROM log_table t;

【讨论】:

  • 它很难测试,但它可以工作。而且效果很快!
【解决方案3】:

一种方法使用join 和聚合:

select t.*
from (select l.tmstmp, count(*)
      from log_table l join
           log_table l2
           on l2.tmstmp >= l.tmstmp and
              l2.tmstmp < l.tmstmp + interval '1' minute
      group by l.tmpstmp
      order by count(*) desc
     ) t
where rownum = 1;

注意:这假定tmstmp 在每一行上都是唯一的。如果这不是真的,那么子查询应该由唯一的某个列聚合。

编辑:

对于大数据,有一种更有效的方法可以利用累积和:

select tmstamp - interval 1 minute as starttm, tmstamp as endtm, cumulative
from (select tmstamp, sum(inc) over (order by tmstamp) as cumulative
      from (select tmstamp, 1 as inc from log_table union all
            select tmstamp + interval '1' day, -1 as inc from log_table
           ) t
      order by sum(inc) over (order by tmstamp) desc
     ) t
where rownum = 1;

【讨论】:

  • 谢谢。非常彻底的答案..虽然不起作用..您在间隔参数+ interval '1'周围缺少'引号..拳头sql永远存在60k记录..我正在调查它atm..第二个只返回1条记录
猜你喜欢
  • 2018-04-06
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-02-09
相关资源
最近更新 更多