有意思的增量计算算法

问题场景

假设有一张表(user_info),其数据结构如下

last_login_time记录的是每个用户最后一次登录时间。现在有这样一组标签"1天内","1~3天","3天以上"来描述用户登录日期和当前日期之间的差值,且为了保证查询的效率,需要将每个用户的登录标签提前计算出来并存储,方便前端高效查询,存储的表(user_tag)结构为
请问该如何实现。

普通的方式

每天将每个用户的最后登录日期和今天进行比较,计算出其登录标签,sql伪代码如下:

select case when 0=<datediff(now(),last_login_time)<1 then '1天内' when 1=<datediff(now(),last_login_time)<3 then '1~3天' when 3=<datediff(now(),last_login_time) then '3天以上' from user_info

这种方式,每天都对所有用户全量计算出标签,在插入user_tag时,要么先全部丢弃掉user_tag表的数据,全新插入今天的数据。要么将今天的数据同昨天的数据进行差值计算,只对user_tag表更新有标签变更的用户。这种方式的缺点是,当数据量过大时,有很大的性能问题,每天都是基于全量用户数据进行各种计算,无论是全量插入user_tag,还是今天的全量很昨天全量进行差值计算,都是很耗时的。

更优雅的方式

"1天内","1~3天","3天以上"这组标签,其数学表示为三个左闭右开的区间,[0,1),[1,3),[3,+∞)。每天计算标签时,我们可以先计算出当天,满足以上三个区间闭的那一端,其对应的最后登录日期。假设今天是2017-5-5号,那么刚刚满足每个区间的对应登录日期分别应,(2017-5-5)-0,(2017-5-5)-1,(2017-5-5)-3,计算结果如下

[0,1) 2017-5-5 [1,3) 2017-5-4 [3,+∞) 2017-5-2

然后拿着这三个日期去user_info表中查询,如果用户的last_login_time等于这三个日期中的任意一个,则给其打上对应的标签。由于每天都在计算,那么那些不能匹配以上日期的用户,说明其之前已经进入了某个标签区间,计算当天不需要变更。sql伪代码如下

select case last_login_time when 2017-5-5 then '1天内' when 2017-5-4 then '1~3天'      when 2017-5-2 then '3天以上' from user_info

这样的计算方式,能只找出那些刚好满足某个区间,应该进行标签变更的用户,即是增量数据,其数据量比之前的全量计算,会小很多。