获取连续登陆天数,连续签到天数 ,方法优化

获取连续登陆天数,连续签到天数,类似这样的需求应该是一个常见的需求,那么我们有没有一套成熟的解决方案呢 ?下面我来跟大家分享一下我的故事。

在猴年马月的一天,有个用户反馈个人中心打开缓慢,需要7、8秒,做为一个认真负责任的程序员GG,我尼玛放下手中的其他工作,跟踪调查并且解决该问题。

第一步重现问题:

  连着登陆了好几个账号到个人中心,打开都不慢呀 ,那是什么问题呢,就你一个人出问题,是你人品差吧,正当打算以此敷衍用户的时候,测试组的小陶说,他也遇到了这个问题,纳尼 !!你个人品差的家伙 ,让俺来看看,你要重现不了,看我不打死你。 于是他登陆账号试了一下,果然是有些缓慢,大概在4、5秒的样子,嗯,至此,这个问题重现成功了 。嗯,厉害 。

第二步查找问题根本原因:

   总不是这两个人人品都差吧,经过一番严密的调查,问题最终锁定在获取连续签到次数上,别问我怎么查到的,因为这两个奇葩居然做到连续签到近100天的牛逼战绩,然后获取连续签到的存储过程采用的循环算法是连续登陆天数越多,算法复杂度就越高。下面贴存储过程代码:

 1  --循环法

declare @day int  = 1, --
 2 @userId int =1,  --用户id
 3 @count int = 0 ,  --连续签到多少天
 4 @isSinginToday int  --今天是否签到
 5
 6 while  exists ( select * from  #SignInLog
 7     where UserId  = @UserId and DATEDIFF(day ,createtime  ,getdate() ) = @day    )
 8 begin
 9     set @count = @count + 1      -- 【循环方法】
10     set @day = @day + 1  --
11 end
12
13 select @isSinginToday =COUNT(*)  from  #SignInLog    where UserId  = @UserId  and DATEDIFF(day ,createtime ,getdate() ) = 0  --今天是否登录
14
15
16 select  @isSinginToday , --当天是否签到
17 @count + @isSinginToday  -- 连续签到n天

把表结构也贴出来吧 ,省得你们这些懒人造数据麻烦,检验代码麻烦

--用户签到日志表
create table #SignInLog (   UserId  int,  --用户id
CreateTime  datetime )--签到时间
insert into #SignInLog  values
(1,‘20160924‘ ),
(1,‘20160923‘ ),
(1,‘20160922‘ ),
(1,‘20160921‘ ),
(1,‘20160919‘ ),
(2,‘20160924‘ ),
(2,‘20160923‘ ),
(2,‘20160920‘ )

可以看到这个存储过程采用循环的方法,去检查前一天是否签到,有的话继续查前一天,并把用于统计连续签到天数的计数器加一 ,前一天没有签到的话作为退出循环的条件,真是段思路清晰的好代码。但是随着连续次数的增多,select语句的执行次数也会增多,所以才会出现了那些连续签到天数多的人缓慢,连续签到天数少的人正常的情况 。 嗯....... 原因也找到了。喝杯茶压压惊先。

最后一步了,也是最难的,解决问题:

  这代码也没毛病,不换个思路的话,问题应该也得不到解决。正当我绞尽脑汁的时候,我有点想上厕所了,正当我上厕所的时候,灵感来了,(为了有意让灵感发生在洗手间,容易吗我)一个sql的函数映入我的眼帘,rownumber()  。于是最后给这个方法取的名字就叫rownumber法。看代码:

--【row_number 法 】
declare @now datetime  = getdate() ,
@count int ,
@userid int = 1 ,
@isSinginToday int
select @count  = count(*) from (
    select  datediff( day  , CreateTime  , @now )         aa ,  --签到时间对比今天的差值
        row_number() over (order by createtime  desc )    bb    --排序字段
    from  #SignInLog
    where UserId  = @userId   and  datediff( day , CreateTime , @now )  > 0  --条件排除今天的签到记录
) T where aa = bb  

select @isSinginToday =COUNT(*)  from  #SignInLog    where UserId  = @UserId  and DATEDIFF(day ,createtime ,getdate() ) = 0  --今天是否登录

select  @isSinginToday , --当天是否签到
@count + @isSinginToday  -- 连续签到n天

这代码思路也算清晰的, 同学们,不知道你们看完这个故事,学到了没。

时间: 2024-11-13 08:14:07

获取连续登陆天数,连续签到天数 ,方法优化的相关文章

oracle计算连续登陆/上班天数

现在有一个计算用户连续上班天数的报表,发现通过用row_number分析函数可以完美计算这个问题. 这个SQL可以解决计算用户连续登陆.签到.上班.旷工等问题. 首先将row_number按照日期排序 将日期的日,比如2016-7-1,将1截取出来转换成数字 把这个日期数字减去row_number计算出来值,作为分组号,因为不连续的值算出来的分组号就不一致: 根据分组号字段进行group by,可以算出每段连续上班的开始.结束时间.天数 如原数据是这样的 2016/7/1 2016/7/2 20

连续时间查询问题-查询一个用户连续登陆天数超过N天的用户

问题:比如查询一个用户连续登陆天数超过7天的用户,或者查询连续在7天的某个时间段登陆的用户. 网上查询sql的语句的用法,对于hive来说也可以试试,查询词"SQL 连续天数查询" 如果使用hadoop如何解决?? 思路(以连续N天登陆为例): 1.计算出每天登陆的用户集合 1.使用MR,第一个job(map以日期为key,对用户进行分组输出.reduce设计:内部构造一个以N容量大小的列表(作为队列),模拟一下啊(日期过来就是有序的,从小到大) 1)第一个日期过来,放在list里面,

统计连续签到的方法

/** * 从最后一次签到时间反推连续签到天数 * * @param list * List<Date> * @param asc * boolean (true:ASC,false:DESC) 对list的描述,是升序还是降序 * @return * * */ public static Map<String, Object> calcuContinue(List<Date> list, boolean asc) { Date end = new Date(); Da

Redis简单案例(三) 连续登陆活动的简单实现

连续登陆活动,或许大家都不会陌生,简单理解就是用户连续登陆了多少天之后,系统就会送一些礼品给相应的用户.最常见的 莫过于游戏和商城这些.游戏就送游戏币之类的东西,商城就送一些礼券.正值国庆,应该也有不少类似的活动. 下面就对这个的实现提供两个思路,并提供解决方案. 思路1(以用户为维度): 连续登陆活动,必然是要求连续登陆,不能有间隔.用1表示登陆,0表示没有登陆,这样我们可以为每个用户创建一个key去存储 他的登陆情况,就可以得到类似这样的一个二进制序列:1110111,如果是7个1,就表示连

PHP如何获取二个日期的相差天数?

PHP如何获取二个日期的相差天数? 我们经常需要获取二个日期之间相差的天数,方便客户知道距离某个时间段是相差了多少天数,这样的显示结果现在是越来越流行的了.不再像以前那样呆板的显示日期的了.我们这里就分享了二种方法可以获取到二个日期之间的相差天数. 第一种: 01 <?php 02 function count_days($a,$b){ 03     $a_dt = getdate($a); 04     $b_dt = getdate($b); 05     $a_new = mktime(1

java获取客户端登陆地址信息(国家、省份、城市等)

原文:java获取客户端登陆地址信息(国家.省份.城市等) 源代码下载地址:http://www.zuidaima.com/share/1550463687658496.htm /** * @param urlStr * 请求的地址 * @param content * @author www.zuidaima.com * 请求的参数 格式为:name=xxx&pwd=xxx * @param encoding * 服务器端请求编码.如GBK,UTF-8等 * @return */ privat

java计算两个日期之间相差天数和相隔天数详解

大家看到文章标题"两个日期之间相差天数和相隔天数",是否有疑惑呢!从中文字面理解,"相差"和"相隔"是有区别的,然而就是这些区别害死很多人,却没有发现,在大量新增统计时是差之毫厘谬以千里,我能都发现是因为一个偶然的机会,一个项目运行几年却没有人发现,我在其中还不到一年,一开始写这些这代码的人根本没分清楚什么情况就写了,怪不得统计的数据总是有那么细微的差别,在于日期"相差"和"相隔"有某些特定的情况下是相等的

PHP中获取文件扩展名的N种方法

PHP中获取文件扩展名的N种方法 从网上收罗的,基本上就以下这几种方式: 第1种方法: function get_extension($file) { substr(strrchr($file, '.'), 1); } 第2种方法: function get_extension($file) { return substr($file, strrpos($file, '.')+1); } 第3种方法: function get_extension($file) { return end(expl

驱动中获取PsActiveProcessHead变量地址的五种方法也可以获取KdpDebuggerDataListHead

PsActiveProcessHead的定义: 在windows系统中,所有的活动进程都是连在一起的,构成一个双链表,表头是全局变量PsActiveProcessHead,当一个进程被创建时,其ActiveProcessList域将被作为节点加入到此链表中:当进程被删除时,则从此链表中移除,如果windows需要枚举所有的进程,直接操纵此链表即可. 方法一:从KdInitSystem函数地址处硬编码搜索 方法二:从System进程(pid=4)的PEPROCESS地址获取 方法三:从ntoskr