Session重疊問題學習(七)--小花狸合併演算法和最後一次優化
接前文
Session重疊問題學習(二),這是問題和需求的描述,執行時間90秒
http://blog.itpub.net/29254281/viewspace-2150229/
Session重疊問題學習(三)--優化,一次優化後,執行時間25秒
http://blog.itpub.net/29254281/viewspace-2150259/
Session重疊問題學習(四)--再優化,二次優化後,執行時間10秒
http://blog.itpub.net/29254281/viewspace-2150297/
Session重疊問題學習(五)--最優化,三次優化後,執行時間1.6秒
http://blog.itpub.net/29254281/viewspace-2150339/
Session重疊問題學習(六)--極致優化,四次優化後,執行時間1250-1300毫秒
http://blog.itpub.net/29254281/viewspace-2150364/
這是對這個問題的演算法總結和最後一次優化.
經過這次優化,在我的電腦上(SSD硬碟,機械硬碟還是沒有這麼快),執行時間是980毫秒左右.真正意義上的秒出.並且我確實覺得是優無可優了。
之所以能從10秒的版本,跳躍優化到1.6s,1.3s的版本.是因為採用了小花狸Session合併演算法。
假如使用者間首尾時間段沒有重複的情況下,滿足如下的規律
但是該規律僅僅存在於使用者首尾時間段不重合的情況.
比如A使用者上線時間是 10點至11點整,而使用者B上線時間是11點整到12點.
因為11點整這個時刻,使用者A和B重合了,所以這個演算法就不能生效了.
所以當時取巧,如果重合了,就增加或者減去一個很小的時間
s+interval startnum/1000000 second s,
e-interval endnum/1000000 second e
但是這樣引入一個問題,就是有誤差.誤差只能縮小卻不能消除.
這也是為什麼1.3s和1.6s版本使用timestamp(6)的原因,就是為了縮小誤差.
但是經過反覆的思考,之前發現的規律其實是一個特例.
小花狸Session合併的通用情況其實是下圖所示
先給每個點標號.
每個點,如果是開始點則+1,結束點則-1.
以圖中左側第二點為例,該點是四個點的重合,其中有一個結束點(-1)三個開始點(+3),所以該點標號是2.
然後從左到右計算,
最左點是0加上該點標號,作為右側點的最大線上人數.
其他點的最大線上人數 都是左側點的最大線上人數加上標號.
最後查詢最大線上人數大於等於2的時間段,彙總即可。
改進的過程如下:
耗時分析:
填充tmp_s,合併同一房間同一使用者的重疊部分,耗時639毫秒
填充t1,拆分跨天的使用者資料,耗時62毫秒
填充tmp_time_point,寫入開始節點和結束節點的資訊和權重,耗時忽略不計
填充t2,計算每個點的標號.耗時78毫秒
填充tmp_min_range,計算最小間隔範圍,耗時125毫秒
小花狸合併演算法並展示,耗時266毫秒.
總計時長983毫秒.
好了,這個問題不能再玩了..over,over
Session重疊問題學習(二),這是問題和需求的描述,執行時間90秒
http://blog.itpub.net/29254281/viewspace-2150229/
Session重疊問題學習(三)--優化,一次優化後,執行時間25秒
http://blog.itpub.net/29254281/viewspace-2150259/
Session重疊問題學習(四)--再優化,二次優化後,執行時間10秒
http://blog.itpub.net/29254281/viewspace-2150297/
Session重疊問題學習(五)--最優化,三次優化後,執行時間1.6秒
http://blog.itpub.net/29254281/viewspace-2150339/
Session重疊問題學習(六)--極致優化,四次優化後,執行時間1250-1300毫秒
http://blog.itpub.net/29254281/viewspace-2150364/
這是對這個問題的演算法總結和最後一次優化.
經過這次優化,在我的電腦上(SSD硬碟,機械硬碟還是沒有這麼快),執行時間是980毫秒左右.真正意義上的秒出.並且我確實覺得是優無可優了。
之所以能從10秒的版本,跳躍優化到1.6s,1.3s的版本.是因為採用了小花狸Session合併演算法。
假如使用者間首尾時間段沒有重複的情況下,滿足如下的規律
但是該規律僅僅存在於使用者首尾時間段不重合的情況.
比如A使用者上線時間是 10點至11點整,而使用者B上線時間是11點整到12點.
因為11點整這個時刻,使用者A和B重合了,所以這個演算法就不能生效了.
所以當時取巧,如果重合了,就增加或者減去一個很小的時間
s+interval startnum/1000000 second s,
e-interval endnum/1000000 second e
- insert into t2 (roomid,s,e)
- select roomid,
- s+interval startnum/1000000 second s,
- e-interval endnum/1000000 second e
- from (
- select
- roomid,
- s,e,
- startnum,
- case when @eflag=eflag then @rn:=@rn+1 when @eflag:=eflag then @rn else @rn end endnum
- from (
- select * from (
- select case when @sflag=sflag then @rn:=@rn+1 when @sflag:=sflag then @rn else @rn end startnum,roomid,s,e,sflag,eflag from
- (
- select * from
- (
- select t1.*,concat('[',roomid,'],',s) sflag,concat('[',roomid,'],',e) eflag from t1 order by roomid ,sflag
- )a,(select @sflag:='',@rn:=0,@eflag:='') vars
- ) b
- ) bb order by roomid,eflag
- ) c
- ) d ;
但是這樣引入一個問題,就是有誤差.誤差只能縮小卻不能消除.
這也是為什麼1.3s和1.6s版本使用timestamp(6)的原因,就是為了縮小誤差.
但是經過反覆的思考,之前發現的規律其實是一個特例.
小花狸Session合併的通用情況其實是下圖所示
先給每個點標號.
每個點,如果是開始點則+1,結束點則-1.
以圖中左側第二點為例,該點是四個點的重合,其中有一個結束點(-1)三個開始點(+3),所以該點標號是2.
然後從左到右計算,
最左點是0加上該點標號,作為右側點的最大線上人數.
其他點的最大線上人數 都是左側點的最大線上人數加上標號.
最後查詢最大線上人數大於等於2的時間段,彙總即可。
改進的過程如下:
- DELIMITER $$
- CREATE DEFINER=`root`@`localhost` PROCEDURE `p`()
- BEGIN
- drop table if exists t1;
- drop table if exists t2;
- drop table if exists tmp_time_point;
- drop table if exists tmp_min_range;
- drop table if exists tmp_s;
- CREATE temporary TABLE `t1` (
- `roomid` int(11) NOT NULL DEFAULT '0',
- `userid` bigint(20) NOT NULL DEFAULT '0',
- `s` timestamp,
- `e` timestamp,
- primary key(roomid,userid,s,e)
- ) ENGINE=memory;
- CREATE temporary TABLE `t2` (
- `roomid` int(11) NOT NULL DEFAULT '0',
- `timepoint` timestamp,
- c int,
- key(roomid,timepoint)
- ) ENGINE=memory;
- CREATE temporary TABLE `tmp_min_range` (
- `roomid` int(11) NOT NULL DEFAULT '0',
- `s` timestamp,
- `e` timestamp,
- primary key(roomid,s,e),
- key(roomid,e)
- ) ENGINE=memory;
- create temporary table tmp_time_point(
- roomid bigint,
- timepoint timestamp,
- type smallint,
- key(roomid,timepoint)
- ) engine=memory;
- create temporary table tmp_s(
- roomid bigint,
- userid bigint,
- s timestamp,
- e timestamp,
- i int
- ) engine=memory;
- SET @A=0;
- SET @B=0;
- insert into tmp_s
- SELECT x.roomid,x.userid,s,e,datediff(e,s)+1 i
- FROM
- (
- (
- SELECT @B:=@B+1 AS id,roomid,userid,s
- FROM (
- SELECT DISTINCT roomid, userid, roomstart AS s
- FROM u_room_log a
- WHERE NOT EXISTS (SELECT *
- FROM u_room_log b
- WHERE a.roomid = b.roomid
- AND a.userid = b.userid
- AND a.roomstart > b.roomstart
- AND a.roomstart <= b.roomend)
- ) AS p
- ) AS x,
- (
- SELECT @A:=@A+1 AS id,roomid,userid,e
- FROM
- (
- SELECT DISTINCT roomid, userid, roomend AS e
- FROM u_room_log a
- WHERE NOT EXISTS (SELECT *
- FROM u_room_log b
- WHERE a.roomid = b.roomid
- AND a.userid = b.userid
- AND a.roomend >= b.roomstart
- AND a.roomend < b.roomend)
- ) AS o
- ) AS y
- )
- WHERE x.id = y.id AND x.roomid = y.roomid AND x.userid = y.userid ;
- select max(i) into @c from tmp_s;
- insert ignore into t1(roomid,userid,s,e)
- select
- roomid, userid,
- if(date(s)!=date(e) and id>1,date(s+interval id-1 day),s) s,
- if(date(s+interval id-1 day)=date(e) ,e,date_format(s+interval id-1 day,'%Y-%m-%d 23:59:59')) e
- from tmp_s t1 STRAIGHT_JOIN
- nums on(nums.id<=t1.i)
- where nums.id<=@c
- ;
- -- 開始點+1,結束點-1
- insert into tmp_time_point(roomid,timepoint,type) select roomid,s,1 from t1;
- insert into tmp_time_point(roomid,timepoint,type) select roomid,e,-1 from t1;
- -- 計算每個點的標號
- insert into t2(roomid,timepoint,c)
- select roomid,timepoint,sum(type) from tmp_time_point group by roomid,timepoint;
- -- 計算最小範圍
- insert ignore into tmp_min_range(roomid,s,e)
- select roomid,starttime starttime, endtime endtime from (
- select
- if(@roomid=roomid,@d,'') as starttime,@d:=str_to_date(timepoint,'%Y-%m-%d %H:%i:%s.%f'),@roomid:=roomid,p.roomid,str_to_date(timepoint,'%Y-%m-%d %H:%i:%s.%f') endtime
- from tmp_time_point p,(select @d:='',@roomid:=-1) vars
- order by roomid,timepoint
- ) v4 where starttime!='' and date(starttime)=date(endtime);
- select roomid,date(s) dt,round(sum(timestampdiff(second,date_format(s,'%Y-%m-%d %H:%i:%s'),date_format(e,'%Y-%m-%d %H:%i:%s')))/60) ts,max(num) c from
- (
- select a.roomid,num,a.s,a.e from (
- select case when @roomid=roomid and date(@timepoint)=date(timepoint) then @num:=@num+prevC when @roomid:=roomid then @num:=0 end num,@timepoint:=timepoint ,a.* from (
- select case when @roomid=roomid then @prevC when @roomid:=roomid then @prevC:=0 end prevC,@prevC:=c,b.* from (
- select * from t2 ,(select @roomid:=-1,@timepoint:='',@num:=0,@prevC:=-1) vars
- ) b order by roomid,timepoint
- ) a order by roomid,timepoint
- ) c
- inner join
- tmp_min_range a on( c.timepoint=a.e and c.roomid=a.roomid)
- where num>=2
- ) d group by roomid,date(s);
- END
耗時分析:
填充tmp_s,合併同一房間同一使用者的重疊部分,耗時639毫秒
填充t1,拆分跨天的使用者資料,耗時62毫秒
填充tmp_time_point,寫入開始節點和結束節點的資訊和權重,耗時忽略不計
填充t2,計算每個點的標號.耗時78毫秒
填充tmp_min_range,計算最小間隔範圍,耗時125毫秒
小花狸合併演算法並展示,耗時266毫秒.
總計時長983毫秒.
好了,這個問題不能再玩了..over,over
來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/29254281/viewspace-2150403/,如需轉載,請註明出處,否則將追究法律責任。
相關文章
- Session重疊問題學習(五)--最優化Session優化
- Session重疊問題學習(三)--優化Session優化
- Session重疊問題學習(四)--再優化Session優化
- Session重疊問題學習(九)--該問題第七次優化.優化合並演算法Session優化演算法
- Session重疊問題學習(六)--極致優化Session優化
- Session重疊問題學習(一)Session
- Session重疊問題學習(八)--該問題第六次優化和Oracle版本Session優化Oracle
- 小花狸監控之MySQLMySql
- 小花狸監控之加密加密
- 小花狸監控之RedisRedis
- 小花狸監控之MongodbMongoDB
- (合併 重疊陣列)練習容器的用法陣列
- 一次UnionAll的合併優化優化
- 小花狸ITPUB部落格備份工具
- 小花狸監控之網路收發
- 記一次Git分支合併引起的問題和修復Git
- 數值最優化—優化問題的解(二)優化
- 演算法權重和問題演算法
- 走近流行強化學習演算法:最優Q-Learning強化學習演算法
- 小花狸監控之安全加固expect備份指令碼指令碼
- 記錄一次SQL函式和優化的問題SQL函式優化
- webpack dll打包重複問題優化Web優化
- 深度學習 - 常用優化演算法深度學習優化演算法
- 記一次Prometheus代理效能優化問題Prometheus優化
- Vue原始碼學習(七):合併生命週期(混入Vue.Mixin)Vue原始碼
- PHP Session可能會引起併發問題PHPSession
- 禁用 COOKIE 後如何訪問 SESSION 問題CookieSession
- 一本組合學習題集——《組合問題與練習》
- 深度學習優化演算法總結深度學習優化演算法
- 優化學習率相關演算法優化演算法
- Java多執行緒學習(七)併發程式設計中一些問題Java執行緒程式設計
- SQL優化--not in和or出的問題SQL優化
- 智慧家居泡沫:安全和隱私問題最嚴重
- 演算法學習之路|日期問題演算法
- 段合併優化及注意事項優化
- Java學習--Cookie 和sessionJavaCookieSession
- Nginx併發訪問優化Nginx優化
- 石子合併問題 (樸素區間DP&&GarsiaWachs演算法)演算法