最近在做一個(gè)游戲數(shù)據(jù)統(tǒng)計(jì)后臺(tái),最基礎(chǔ)的功能是通過分析注冊登錄日志來展示用戶數(shù)據(jù)。在公司內(nèi)部測試,用戶量很少,所以就沒有發(fā)現(xiàn)什么性能問題。但是這兩天一起放到真實(shí)的測試環(huán)境,用戶量噌噌地就涌進(jìn)來了,從下午開始,在線人數(shù)的統(tǒng)計(jì)開始卡,幾秒鐘才返回?cái)?shù)據(jù);注冊人數(shù)的查詢速度還行。到了晚上,在線人數(shù)的統(tǒng)計(jì)基本上就加載超時(shí)打不開了。雖然不知他們游戲端那邊什么BUG,玩家那邊登錄經(jīng)常出問題,導(dǎo)致在線人數(shù)和注冊人數(shù)并不是很多。但是就這一點(diǎn)數(shù)據(jù)量我這邊查詢的速度也不行,這就很尷尬了。
現(xiàn)在他們那邊在查游戲的BUG,我這邊也在看統(tǒng)計(jì)后臺(tái)的代碼到底性能出在哪里。首先說明一下,我統(tǒng)計(jì)用的數(shù)據(jù)是從庫,他們游戲用的是主庫,再說我這邊管理員人數(shù)就幾個(gè),不可能會(huì)影響到游戲服的性能問題。
今天項(xiàng)目組長把數(shù)據(jù)庫都導(dǎo)過來到公司內(nèi)的服務(wù)器。我拷了一份到本機(jī),看看統(tǒng)計(jì)平臺(tái)的性能問題出在哪里。然后卻發(fā)現(xiàn),居然連注冊統(tǒng)計(jì)都非常卡,服務(wù)器上是兩秒左右返回,本機(jī)要二十幾秒,還經(jīng)常超時(shí)(PHP的默認(rèn)配置是30秒超時(shí));在線統(tǒng)計(jì)的就不用說了肯定打不開??戳艘幌聰?shù)據(jù)庫,當(dāng)天的注冊記錄也就 3500 條左右(有假數(shù)據(jù)),每五分鐘統(tǒng)計(jì)一次,一天就是統(tǒng)計(jì) 288 次。當(dāng)然這里肯定不是循環(huán)查詢數(shù)據(jù)庫288次,那樣會(huì)被罵死的吧。
統(tǒng)計(jì)時(shí)間段內(nèi)的注冊數(shù),邏輯也非常簡單,就是每個(gè)時(shí)間段遍歷一次數(shù)據(jù),比較時(shí)間大小,符合就+1。但是為什么這么簡單的邏輯,也就一百萬次循環(huán),怎么會(huì)跑出了足足半分鐘的時(shí)間那么久呢?
關(guān)鍵問題就出在于 時(shí)間比較這里了,我們都知道,時(shí)間戳是比較時(shí)間大小的一個(gè)比較科學(xué)的方法,而數(shù)據(jù)庫里記錄的時(shí)間一般都是以 YYYY-mm-dd HH:ii:ss 的形式,PHP里有strtotime的函數(shù)轉(zhuǎn)換成時(shí)間戳。然而在288個(gè)for * 3500個(gè)foreach 的加持之后,這里的執(zhí)行時(shí)間長達(dá)半分鐘。
$nowDayDT = strtotime( date('Y-m-d') ); $__startT = microtime(TRUE); for($i=0; $i<$allTime;