千家信息网

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

发表于:2025-02-02 作者:千家信息网编辑
千家信息网最后更新 2025年02月02日,接前文:需求描述和第一版解决方案(执行时间90秒)http://blog.itpub.net/29254281/viewspace-2150229/优化和修改bug的版本(执行时间25秒)http:/
千家信息网最后更新 2025年02月02日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,as DATETIME) starttime,as DATETIME) endtime from (
  2. select @d as starttime,@d:=d,v3.roomid,v3.d endtime from (
  3. select distinct roomid,
  4. when nums.id=1 then v1s
  5. when nums.id=2 then v1e
  6. when nums.id=3 then v2s
  7. when nums.id=4 then v2e
  8. end d from (
  9. select v1.roomid, v1.s v1s,v1.e v1e,v2.s v2s,v2.e v2e
  10. from t1 v1
  11. 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)
  12. where v2.roomid in(select distinct roomid from t1 where date(s)=pTime)
  13. and v2.s>=pTime and v2.s<(pTime+interval '1' and (v2.roomid,v2.userid,v2.s,v2.e)!= (v1.roomid,v1.userid,v1.s,v1.e)
  14. ) a,nums where nums.id<=4
  15. order by roomid,d
  16. ) v3,(select @d:='') vars
  17. ) v4 where starttime!=''

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

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

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

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

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

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

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

三次测试耗时均低于 10.3秒



0