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/
週五晚上終於把這個演算法初步實現了.
連續加班忙碌了一個星期,終於有點曙光了.
從這個問題的緣起,到目前應該已經優化了快100倍了
但是週末的時候,想想還是不對.
小花狸Session合併演算法(對,以後這個演算法就叫這個名稱了)實現的合併速度應該是非常快的.代價僅僅是掃描一遍記錄.
這1.6秒到底用在哪裡了?
後來經過反覆除錯.發現還有兩塊可以優化改進的地方.
改進後的過程如下:
第一處改進
原來同一房間同一使用者重疊時間合併,然後再拆分跨天資料,用的是一條SQL
現在改進如下
先把同一房間同一使用者的重疊部分合並,然後暫存臨時表
記錄最大的間隔時間,然後再拆分資料
拆分資料的時候 使用STRAIGHT_JOIN 強制連線順序.
這樣避免因為數字輔助表過大,而導致效能陡然變差.
第二處改進
原來使用distinct的查詢, 都改為在臨時表上增加主鍵.
然後使用insert ignore into 代替 insert into
這樣大概優化了300毫秒
經過反覆優化之後,執行時間大致穩定在1250毫秒 至 1300 毫秒
各個部分耗時分析如下
填充tmp_s,合併同一房間同一使用者的重疊部分,耗時655毫秒
填充t1,拆分跨天的使用者資料,耗時62毫秒
填充t2,使用者時間段首尾相交或者首尾全部重合的資料拆分,耗時140毫秒
填充tmp_min_range,計算最小間隔範圍,耗時156毫秒
小花狸Session合併演算法,耗時219毫秒
結果統計展示,耗時47毫秒
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/
週五晚上終於把這個演算法初步實現了.
連續加班忙碌了一個星期,終於有點曙光了.
從這個問題的緣起,到目前應該已經優化了快100倍了
但是週末的時候,想想還是不對.
小花狸Session合併演算法(對,以後這個演算法就叫這個名稱了)實現的合併速度應該是非常快的.代價僅僅是掃描一遍記錄.
這1.6秒到底用在哪裡了?
後來經過反覆除錯.發現還有兩塊可以優化改進的地方.
改進後的過程如下:
- drop procedure p;
- DELIMITER $$
- CREATE DEFINER=`root`@`localhost` PROCEDURE `p`()
- BEGIN
- declare done int default 0;
- declare v_roomid bigint;
- declare v_time timestamp(6);
- declare v_cur_type smallint;
- declare v_before_roomid bigint default -1;
- declare v_before_type smallint default -1;
- declare v_before_time timestamp(6) ;
- declare v_num bigint default 0;
- declare cur_test CURSOR for select roomid,type,timepoint from tmp_time_point order by roomid,timepoint,type ;
- DECLARE CONTINUE HANDLER FOR NOT FOUND SET done = 1;
- drop table if exists t1;
- drop table if exists t2;
- drop table if exists tmp_time_point;
- drop table if exists tmp_result;
- 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(6),
- `e` timestamp(6),
- primary key(roomid,userid,s,e)
- ) ENGINE=memory;
- CREATE temporary TABLE `t2` (
- `roomid` int(11) NOT NULL DEFAULT '0',
- `s` timestamp(6),
- `e` timestamp(6)
- ) ENGINE=memory;
- CREATE temporary TABLE `tmp_min_range` (
- `roomid` int(11) NOT NULL DEFAULT '0',
- `s` timestamp(6),
- `e` timestamp(6),
- primary key(roomid,s,e),
- key(roomid,e)
- ) ENGINE=memory;
- create temporary table tmp_time_point(
- roomid bigint,
- timepoint timestamp(6),
- type smallint,
- key(roomid,timepoint)
- ) engine=memory;
- create temporary table tmp_result(
- roomid bigint,
- timepoint timestamp(6),
- c int
- ) 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
- ;
- 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 ;
- insert into tmp_time_point(roomid,timepoint,type) select roomid,s,1 from t2;
- insert into tmp_time_point(roomid,timepoint,type) select roomid,e,0 from t2;
- 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);
- open cur_test;
- repeat
- fetch cur_test into v_roomid,v_cur_type,v_time;
- if done !=1 then
- -- 第一行或者每個房間的第一行
- if v_before_roomid=-1 or v_roomid!=v_before_roomid then
- set v_before_roomid:=v_roomid;
- set v_before_type:=1;
- set v_before_time:='0000-00-00 00:00:00';
- set v_num:=0;
- end if;
- if v_before_type=1 then
- set v_num:=v_num+1;
- insert into tmp_result(roomid,timepoint,c) values(v_roomid,v_time,v_num);
- end if;
- if v_before_type=0 then
- set v_num:=v_num-1;
- insert into tmp_result(roomid,timepoint,c) values(v_roomid,v_time,v_num);
- end if;
- set v_before_roomid:=v_roomid;
- set v_before_type:=v_cur_type;
- set v_before_time:=v_time;
- end if;
- until done end repeat;
- close cur_test;
- 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(c)-1 c from (
- select a.roomid,a.s,a.e,r.c,r.timepoint from tmp_result r
- inner join
- tmp_min_range a on( r.timepoint=a.e and r.roomid=a.roomid)
- where c>2
- ) a group by roomid,date(s);
- END
第一處改進
原來同一房間同一使用者重疊時間合併,然後再拆分跨天資料,用的是一條SQL
現在改進如下
- 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
- ;
先把同一房間同一使用者的重疊部分合並,然後暫存臨時表
記錄最大的間隔時間,然後再拆分資料
拆分資料的時候 使用STRAIGHT_JOIN 強制連線順序.
這樣避免因為數字輔助表過大,而導致效能陡然變差.
第二處改進
原來使用distinct的查詢, 都改為在臨時表上增加主鍵.
然後使用insert ignore into 代替 insert into
這樣大概優化了300毫秒
經過反覆優化之後,執行時間大致穩定在1250毫秒 至 1300 毫秒
各個部分耗時分析如下
填充tmp_s,合併同一房間同一使用者的重疊部分,耗時655毫秒
填充t1,拆分跨天的使用者資料,耗時62毫秒
填充t2,使用者時間段首尾相交或者首尾全部重合的資料拆分,耗時140毫秒
填充tmp_min_range,計算最小間隔範圍,耗時156毫秒
小花狸Session合併演算法,耗時219毫秒
結果統計展示,耗時47毫秒
來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/29254281/viewspace-2150364/,如需轉載,請註明出處,否則將追究法律責任。
相關文章
- Session重疊問題學習(三)--優化Session優化
- Session重疊問題學習(五)--最優化Session優化
- Session重疊問題學習(四)--再優化Session優化
- Session重疊問題學習(八)--該問題第六次優化和Oracle版本Session優化Oracle
- Session重疊問題學習(一)Session
- Session重疊問題學習(九)--該問題第七次優化.優化合並演算法Session優化演算法
- Session重疊問題學習(七)--小花狸合併演算法和最後一次優化Session演算法優化
- 將MySQL去重操作優化到極致之三彈連發MySql優化
- Session一致性問題Session
- webpack dll打包重複問題優化Web優化
- redis學習(六) 排序(sort,by,store,效能優化)Redis排序優化
- React 同構與極致的效能優化React優化
- 任何事做到極致之sql優化SQL優化
- iOS8 自定義UITabBar (使用popToViewController導致的UITabBarButton重疊的問題)iOSUItabBarViewController
- Shiro效能優化:解決Session頻繁讀寫問題優化Session
- 蝦扯蛋之條件判斷的極致優化優化
- 3倍+提升,高德地圖極致效能優化之路地圖優化
- 分庫分表如何進行極致的優化優化
- 第六章 數學問題 -------- 6.1【巧用進位制】天平稱重問題
- merge語句導致的效能問題緊急優化優化
- 優化由直方圖資訊導致的sql效能問題優化直方圖SQL
- React內部的效能優化沒有達到極致?React優化
- 學習動態效能表(六)-(2)-V$SESSION_EVENTSession
- 凸優化問題優化
- 效能優化問題優化
- 程式設計師修仙之路--把使用者訪問記錄優化到極致程式設計師優化
- 【調優】設計問題還是優化問題?優化
- 【OpenCV學習】計算兩幅影象的重疊區域OpenCV
- 強化學習-學習筆記11 | 解決高估問題強化學習筆記
- LayaAir引擎學習日誌14----LayaAir記憶體優化的問題AI記憶體優化
- 學習動態效能表(六)-(1)-V$SESSION_WAITSessionAI
- 如何避開jquery動態繫結的事件重疊問題jQuery事件
- MySQL優化學習手札(四) 單表訪問方法MySql優化
- session共享問題???Session
- 斜率優化(凸包優化)DP問題acm優化ACM
- android學習之路(六)---- 圖片載入庫的優化、封裝Android優化封裝
- 指令碼錯誤量極致優化-監控上報與Script error指令碼優化Error
- 指令碼錯誤量極致優化 - 監控上報與 Script error指令碼優化Error