PHP的效能大坑--strtotime函數

來源:互聯網
上載者:User

標籤:使用者   ges   自我裝載   line   項目組   科學   平台   註冊   .com   

最近在做一個遊戲資料統計後台,最基礎的功能是通過分析註冊登入日誌來展示使用者資料。在公司自我裝載,使用者量很少,所以就沒有發現什麼效能問題。但是這兩天一起放到真實的測試環境,使用者量噌噌地就湧進來了,從下午開始,線上人數的統計開始卡,幾秒鐘才返回資料;註冊人數的查詢速度還行。到了晚上,線上人數的統計基本上就載入逾時打不開了。雖然不知他們遊戲端那邊什麼BUG,玩家那邊登入經常出問題,導致線上人數和註冊人數並不是很多。但是就這一點資料量我這邊查詢的速度也不行,這就很尷尬了。

現在他們那邊在查遊戲的BUG,我這邊也在看統計背景代碼到底效能出在哪裡。首先說明一下,我統計用的資料是從庫,他們遊戲用的是主庫,再說我這邊管理員人數就幾個,不可能會影響到遊戲服的效能問題。

今天項目組長把資料庫都導過來到公司內的伺服器。我拷了一份到本機,看看統計平台的效能問題出在哪裡。然後卻發現,居然連註冊統計都非常卡,伺服器上是兩秒左右返回,本機要二十幾秒,還經常逾時(PHP的預設配置是30秒逾時);線上統計的就不用說了肯定打不開。看了一下資料庫,當天的註冊記錄也就 3500 條左右(有假資料),每五分鐘統計一次,一天就是統計 288 次。當然這裡肯定不是迴圈查詢資料庫288次,那樣會被罵死的吧。

統計時間段內的註冊數,邏輯也非常簡單,就是每個時間段遍曆一次資料,比較時間大小,符合就+1。但是為什麼這麼簡單的邏輯,也就一百萬次迴圈,怎麼會跑出了足足半分鐘的時間那麼久呢?

關鍵問題就出在於 時間比較這裡了,我們都知道,時間戳記是比較時間大小的一個比較科學的方法,而資料庫裡記錄的時間一般都是以 YYYY-mm-dd HH:ii:ss 的形式,PHP裡有strtotime的函數轉換成時間戳記。然而在288個for * 3500個foreach 的加持之後,這裡的執行時間長達半分鐘

$nowDayDT = strtotime( date(‘Y-m-d‘) );$__startT = microtime(TRUE);for($i=0; $i<$allTime; $i += $gapTime){    $count = 0;    //用於資料比較的    $startDT = $nowDayDT+$i;    $endDT = $nowDayDT+$i+$gapTime;    //用於顯示的    $xAxis1 = date(‘H:i‘, $nowDayDT+$i);    $xAxis2 = date(‘H:i‘, $nowDayDT+$i+$gapTime);    foreach($rawData as $line){        $time = strtotime($line[‘log_dt‘]);        if( $startDT<=$time && $time<$endDT ){            $count ++;        }    }    $resArr[] = [        ‘date‘=>$xAxis1.‘~‘.$xAxis2,        ‘number‘=>$count    ];}echo microtime(TRUE)-$__startT;

那這樣的話,基本上是沒辦法再用這個strtotime的函數的了,那還有什麼辦法比較時間大小呢?答案很簡單粗暴,PHP裡面可以直接比較兩個日期時間字串!所以改過後的代碼如下。然後現在的已耗用時間大概是 0.3秒

$__startT = microtime(TRUE);for($i=0; $i<$allTime; $i += $gapTime){    $count = 0;    //用於資料比較的    $startDT = date(‘Y-m-d H:i:s‘, $nowDayDT+$i);    $endDT = date(‘Y-m-d H:i:s‘, $nowDayDT+$i+$gapTime);    //用於顯示的    $xAxis1 = date(‘H:i‘, $nowDayDT+$i);    $xAxis2 = date(‘H:i‘, $nowDayDT+$i+$gapTime);    foreach($rawData as $line){        $time = $line[‘log_dt‘];        if( $startDT<=$time && $time<$endDT ){            $count ++;        }    }    $resArr[] = [        ‘date‘=>$xAxis1.‘~‘.$xAxis2,        ‘number‘=>$count    ];}echo microtime(TRUE)-$__startT;
去掉strtotime的比較遍曆再最佳化

大家可能發現一個問題,for 裡面嵌套一個 foreach,這效能有點擔憂,其中裡面的 foreach 有必要完全遍曆嗎?其實是不必的。只要查SQL資料的時候,按時間排序排出來。最佳化後的時間比較演算法如下:

for{ ...
foreach($rawData as $line){ $time = $line[‘log_dt‘];//strtotime($line[‘log_dt‘]); //最佳化演算法計算 if($time<$startDT) continue; //小於開始時間則跳過 if($time>=$endDT) break; //大於結束時間則結束 $count ++; //否則為符合條件 //原始的演算法// if( $startDT<=$time && $time<$endDT ){// $count ++;// }}
...}

這裡巧用了 continue 和 break 關鍵字,用於跳過一次迴圈和結束整個迴圈。這次的話,一天中剛開始的時間統計中,後面很大一部分資料的都可以直接跳過。最後總遍曆時間縮短為約0.12秒

總結,在大型的資料處理中,應該盡量避免在遍曆中進行資料的轉換,避免用一些原理複雜的函數。如strtotime

PHP的效能大坑--strtotime函數

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.