实时在线查询sql

场景:经过处理入库的记录都是当时在线的用户数,即一个唯一的uuid就可以表示这是一个当时的在线用户。现在要求查询出

实时在线用户数,这个"实时"肯定是最近的一个时间区间。我们取这个时间区间为5分钟。

 

数据也是5分钟入一次库。更精确的说法是,我们的"实时数据"是最近一次完整的5分钟区间。为什么要强调完整呢?因为入库的

时间并不能和刷新的时间做到同步,有可能页面正在刷新数据的时候,此时最近一次还没有完全入库。假设最后一次5分钟end5min

和倒数第二个5分钟last5min,根据此时的情况,我们会取到last5min和end5min各自一部分的数据,而此时的情况应该是取

last5min阶段入库的数据。

 

如何满足我们的最近"完整"5分钟数据呢?

将今天凌晨到当前时间的记录以5分钟为一组进行分组。

24*60/5=288 

也就是说:一天可以分成288个5分钟的段。

 

假设凌晨时间为date,入库的每条记录的时间字段为logtime。

logtime-to_date(date,'yyyy-mm-dd')

这样就算出了入库时间距离当天凌晨的时间间隔。这个时间间隔是以天为单位的。这个小数就可以看成logtime距离凌晨这段

时间间隔在这一天中所占的比重。于是根据这个时间间隔就可以将logtime进行分组。因为一天的分组为288,如果将logtime

在这一天中所占的比重与总的分组数288相乘,就可以将logtime归于相应的分组当中去。

group_num=trunc((logtime-to_date(date,'yyyy-mm-dd'))*1440/5)

 

算出每一组的在线用户数:count(DISTINCT uuid)

 

此外,我们会定一个定时器,以0点为起点,每5分钟刷新一次页面。

__1__2__3_

假设我们在时间点1刷新了一次数据,那么在页面上就会将时间点1记下来,在下一次查询分组时,就会以时间点1(lastdate)作为查询条件进行查询,找到相应的分组。然而,我们得到的中间表是分组号。于是我们又要根据分组号转换成对应的时间:

logtime=group_num*5/1440+to_date(date,'yyyy-mm-dd')

于是:

SELECT (TO_DATE(date, 'yyyy-mm-dd hh24:mi') + group_num * 5 / (24 * 60)) LOGTIME
所以就可以以时间点1为条件进行查询了。

 

 

具体的sql语句如下:

SELECT num as nowNum FROM ( SELECT (TO_DATE(date, 'yyyy-mm-dd hh24:mi') + group_num * 5 / (24 * 60)) LOGTIME,NUM FROM (SELECT TRUNC((LOGTIME - TO_DATE(date, 'yyyy-mm-dd')) * 1440 / 5) group_num, count(DISTINCT uuid) NUM FROM ONLINE_COUNT WHERE LOGTIME BETWEEN  TO_DATE(date, 'yyyy-MM-dd hh24:mi:ss') AND  sysdate  GROUP BY TRUNC((LOGTIME - TO_DATE(date, 'yyyy-mm-dd')) * 1440 / 5) ORDER BY group_num) T ) WHERE logtime = to_date(lastdate,'yyyy-MM-dd hh24:mi:ss')

 

posted on 2015-06-16 17:38  飞机说之代码也疯狂  阅读(1235)  评论(0编辑  收藏  举报