Session重叠问题学习(四)--再优化

接前文:
需求描述和第一版解决方案(执行时间90秒)
http://blog.itpub.net/29254281/viewspace-2150229/

优化和修改bug的版本(执行时间25秒)
http://blog.itpub.net/29254281/viewspace-2150259/


我觉得在集合思维处理方式中,前文已经达到最优了.

如果放弃完全的集合处理思维,实际上还可以更加的优化.

前文的几个问题.
1.引入了过多的表结构.
2.写表本身也花费了时间.
3.前文按天批处理,粒度还是细了.应该一把批量全出最快.
4.前文计算最小间隔范围的部分,因为应用集合化思维,不好理解性能还差.

前文计算最小间隔范围的部分如下
  1. select roomid,CAST(starttime as DATETIME) starttime,CAST(endtime as DATETIME) endtime from (    
  2.      select @d as starttime,@d:=d,v3.roomid,v3.d endtime from (    
  3.                 select distinct roomid,     
  4.                 case        
  5.                 when nums.id=1 then v1s       
  6.                 when nums.id=2 then v1e       
  7.                 when nums.id=3 then v2s       
  8.                 when nums.id=4 then v2e       
  9.                 end d   from (    
  10.                     select   v1.roomid, v1.s v1s,v1.e v1e,v2.s v2s,v2.e v2e    
  11.                     from t1 v1    
  12.                     inner join t1 v2 on ((v1.s between v2.s and v2.e or v1.e between v2.s and v2.e )  and v1.roomid=v2.roomid)     
  13.                     where v2.roomid in(select distinct roomid from t1 where date(s)=pTime)    
  14.                     and v2.s>=pTime and v2.s<(pTime+interval '1' dayand (v2.roomid,v2.userid,v2.s,v2.e)!= (v1.roomid,v1.userid,v1.s,v1.e)     
  15.                 ) a,nums where nums.id<=4    
  16.                 order by roomid,d    
  17.     ) v3,(select @d:='') vars    
  18. ) v4 where starttime!='' 

该部分使用集合处理方式,不好理解性能还差.

这块可以通过游标写临时表轻易解决。
本质上最小范围就是
每天每个房间每个记录的开始时间和结束时间都扣出来作为一行 排序。

然后找到 每个时间 最近的下一个时间 ,作为最小时间范围.

如果使用游标,遍历一遍即可.

  1. DELIMITER $$  
  2.   
  3. CREATE DEFINER=`root`@`localhost` PROCEDURE `p`()  
  4. BEGIN  
  5.     declare done int default 0;      
  6.     declare v_roomid bigint;  
  7.     declare v_start timestamp;  
  8.     declare v_end timestamp;  
  9.     declare cur_test CURSOR for select roomid,s,e from t1  ;  
  10.   
  11.     DECLARE  CONTINUE HANDLER FOR NOT FOUND  SET done = 1;      
  12.       
  13.     drop table if exists t1;  
  14.     drop table if exists tmp_time_point;  
  15.     CREATE temporary TABLE `t1` (  
  16.       `roomid` int(11) NOT NULL DEFAULT '0',  
  17.       `userid` bigint(20) NOT NULL DEFAULT '0',  
  18.       `s` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,  
  19.       `e` timestamp NOT NULL DEFAULT '0000-00-00 00:00:00',  
  20.       primary KEY `roomid` (`roomid`,`s`,`e`,`userid`)  
  21.     ) ENGINE=InnoDB;  
  22.   
  23.     create temporary table tmp_time_point(  
  24.             roomid bigint,  
  25.             timepoint timestamp,  
  26.             primary key(roomid,timepoint)  
  27.     ) engine=memory;  
  28.   
  29.   
  30. insert into t1  
  31. select distinct    
  32. roomid,    
  33. userid,    
  34. if(date(s)!=date(e) and id>1,date(s+interval id-1 day),s) s,    
  35. if(date(s+interval id-1 day)=date(e) ,e,date_format(s+interval id-1 day,'%Y-%m-%d 23:59:59')) e    
  36. from (    
  37. SELECT DISTINCT s.roomid, s.userid, s.s, (      
  38.         SELECT MIN(e)      
  39.         FROM (SELECT DISTINCT roomid, userid, roomend AS e      
  40.             FROM u_room_log a      
  41.             WHERE NOT EXISTS (SELECT *      
  42.                 FROM u_room_log b      
  43.                 WHERE a.roomid = b.roomid      
  44.                     AND a.userid = b.userid      
  45.                     AND a.roomend >= b.roomstart      
  46.                     AND a.roomend < b.roomend)      
  47.             ) s2      
  48.         WHERE s2.e > s.s      
  49.             AND s.roomid = s2.roomid      
  50.             AND s.userid = s2.userid      
  51.         ) AS e      
  52. FROM (SELECT DISTINCT roomid, userid, roomstart AS s      
  53.     FROM u_room_log a      
  54.     WHERE NOT EXISTS (SELECT *      
  55.         FROM u_room_log b      
  56.         WHERE a.roomid = b.roomid      
  57.             AND a.userid = b.userid      
  58.             AND a.roomstart > b.roomstart      
  59.             AND a.roomstart <= b.roomend)      
  60.     ) s, (SELECT DISTINCT roomid, userid, roomend AS e      
  61.     FROM u_room_log a      
  62.     WHERE NOT EXISTS (SELECT *      
  63.         FROM u_room_log b      
  64.         WHERE a.roomid = b.roomid      
  65.             AND a.userid = b.userid      
  66.             AND a.roomend >= b.roomstart      
  67.             AND a.roomend < b.roomend)      
  68.     ) e      
  69. WHERE s.roomid = e.roomid      
  70.     AND s.userid = e.userid     
  71.     
  72. ) t1 ,    
  73. nums     
  74. where  nums.id<=datediff(e,s)+1    
  75. ;    
  76.   
  77.     open cur_test;      
  78.     repeat      
  79.         fetch cur_test into v_roomid, v_start,v_end;      
  80.         if done !=1 then    
  81.            insert ignore into tmp_time_point(roomid,timepoint) values(v_roomid,v_start);  
  82.            insert ignore into tmp_time_point(roomid,timepoint) values(v_roomid,v_end);  
  83.         end if;    
  84.     until done end repeat;      
  85.     close cur_test;   
  86.       
  87.     
  88.   
  89.    
  90. select roomid,date(s) dt,round(sum(timestampdiff(second,s,e))/60) ts,max(c) c from (       
  91.     select roomid,s,e ,count(distinct userid) c  from (  
  92.         select distinct v6.roomid,v6.userid,greatest(s,starttime) s,least(e,endtime) e  
  93.         from (  
  94.             select distinct roomid,CAST(starttime as DATETIME) starttime,CAST(endtime as DATETIME) endtime from (  
  95.                 select   
  96.                 if(@roomid=roomid,@d,'')  as starttime,@d:=timepoint,@roomid:=roomid,p.roomid,p.timepoint endtime  
  97.                 from tmp_time_point p,(select @d:='',@roomid:=-1) vars  
  98.                 order by roomid,timepoint  
  99.             ) v4 where starttime!='' and date(starttime)=date(endtime)  
  100.         ) v5 inner join t1 v6 on(v5.starttime between v6.s and v6.e and v5.endtime between v6.s and v6.e and v5.roomid=v6.roomid)  
  101.     ) v6 group by roomid,s,e having count(distinct userid)>1     
  102. ) v7 group by roomid,date(s);  
  103.   
  104.   
  105. END  

都内聚到一个过程之后,不需要创建额外的普通表,直接在过程中创建临时表.实现高内聚,低耦合.

call p 
过程返回的结果即为最终结果.

三次测试耗时均低于 10.3秒



来自 “ ITPUB博客 ” ,链接:http://blog.itpub.net/29254281/viewspace-2150297/,如需转载,请注明出处,否则将追究法律责任。

转载于:http://blog.itpub.net/29254281/viewspace-2150297/

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值