标签:
场景:经过处理入库的记录都是当时在线的用户数,即一个唯一的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‘)
标签:
原文地址:http://www.cnblogs.com/feijishuo/p/4581409.html