摘要:記住它,一點(diǎn)點(diǎn)來,萬物均可優(yōu)化。下一篇將為你講解對(duì)一個(gè)萬數(shù)據(jù)的表程序優(yōu)化實(shí)戰(zhàn)真實(shí)例子之二開刀數(shù)據(jù)表完本文原創(chuàng)發(fā)布于微信公眾號(hào)北哥小報(bào)嚴(yán)謹(jǐn)?shù)脑瓌?chuàng)技術(shù)文,還有一些其他研究。
當(dāng)前系統(tǒng)情況這是一篇真實(shí)案例,并不是理論課,阿北將同步我的整個(gè)優(yōu)化之路,優(yōu)化之路慢慢長(zhǎng),對(duì)大家拋磚引玉已達(dá)目的,若你也有一些優(yōu)化思路,請(qǐng)跟貼。
項(xiàng)目是年前一個(gè)朋友做的,客戶也是我的一個(gè)朋友,所以現(xiàn)在來幫忙優(yōu)化,系統(tǒng)很簡(jiǎn)單,就是一個(gè)菜單頁面,客戶下單,然后打印機(jī)出小票,整個(gè)系統(tǒng)使用yii2基礎(chǔ)版 + MySQL5.6.29驅(qū)動(dòng)。
客戶店里每天大約走1.5-2w的流水,現(xiàn)在最大的表有26w數(shù)據(jù),我切圖大家先看下。
從圖例看可能要優(yōu)化的地方
表引擎使用了MyISAM問題
order、order_box數(shù)據(jù)表瓶頸問題
我使用的工具本地環(huán)境MAMP
yii2-debug 神器小強(qiáng)
yii2的各種緩存
優(yōu)化原則代碼的修改最小化,盡量不動(dòng)核心代碼以防止引入bug,最后在進(jìn)行數(shù)據(jù)庫和服務(wù)器的優(yōu)化。
那咱就開始吧~
客戶說后臺(tái)登陸慢當(dāng)我第一次聽客戶這樣說的時(shí)候,就已經(jīng)知道慢的絕對(duì)不是登陸,這個(gè)系統(tǒng)沒有權(quán)限、沒有很多日志、沒有登陸后的事件、僅僅就是一個(gè)登陸而已。
那很可能就是慢在登陸后進(jìn)入的第一個(gè)頁面而給客戶的感覺是登陸慢。
那就看看這個(gè)頁面
頁面邏輯很簡(jiǎn)單,就是一個(gè)銷售圖表,每天的銷售額曲線,那么問題最可能出現(xiàn)在這個(gè)圖表上,畢竟銷售額的計(jì)算看代碼都是從訂單實(shí)時(shí)分析出來的。
用yii2-debug看一看
果不其然,yii2-debug告訴我此action整個(gè)響應(yīng)時(shí)間為2.652秒,而數(shù)據(jù)庫就用了2.518秒,查詢次數(shù)39次...
看看每個(gè)查詢,每一天執(zhí)行一個(gè)SQL語句,每個(gè)都用了90毫秒左右,畢竟是26w數(shù)據(jù)中拿數(shù)據(jù)。
似乎問題明朗了,解決這個(gè)數(shù)據(jù)庫查詢就解決了這個(gè)頁面,先看看這個(gè)圖表的代碼實(shí)現(xiàn)
$y = date("Y",time()); //年 $m = date("m",time()); //月 $days_num = date("t",time()); //當(dāng)月天數(shù) $days = ""; $moneys = ""; for($i=1; $i<=$days_num; $i++){ $days .= $i.","; $begin_time = strtotime($y."-".$m."-".$i) + Yii::$app->params["business_hour"]["begin_time"]; $end_time = strtotime($y."-".$m."-".$i) + Yii::$app->params["business_hour"]["end_time"]; $money = Order::find() ->where([">","dish_id",0]) ->andWhere(["pay_state"=>"pay"]) ->andWhere([">=","pay_time",$begin_time]) ->andWhere(["<=","pay_time",$end_time]) ->andWhere(["store_id"=>Yii::$app->admin->identity->store_id]) ->sum("money"); $moneys .= ($money > 0 ? $money : 0).","; }
優(yōu)化的步驟很簡(jiǎn)單:首先看能不能減少查詢次數(shù),如果不能就加速查詢,如果還不能就緩存結(jié)果。
在這段代碼中,無論今日是幾號(hào),都進(jìn)行了整月天數(shù)的查詢,我先來去掉不該進(jìn)行的查詢。
修改及其簡(jiǎn)單,只是增加了3行代碼
for($i=1; $i<=$days_num; $i++){ $days .= $i.","; if($i > date("d",time())){ $moneys .= "0,"; continue; } ........ }
但是通過減少不必要的查詢的結(jié)果是
數(shù)據(jù)庫檢索從39減少到30次,耗時(shí)從2.518秒減少到1.982秒。
對(duì)于加速查詢無外乎表類型選擇及索引的添加,本著表是所有action的表,蒼老師是世界的蒼老師,我先不動(dòng),只是記錄下dish_id、pay_state、pay_time、store_id四個(gè)字段,后面對(duì)order表進(jìn)行改造的時(shí)候再考慮他們。
然后對(duì)于這種統(tǒng)計(jì)類數(shù)據(jù),沒有必要每次都實(shí)時(shí)讀取,我應(yīng)該加一個(gè)緩存。
加個(gè)文件類型緩存如果你不會(huì)玩Yii2緩存,請(qǐng)移步到 Yii2緩存系列 先學(xué)習(xí)。
看這個(gè)圖表和當(dāng)下代碼,我的緩存可以按照月份來,但是還要保證當(dāng)天銷量的實(shí)時(shí)性,所以我緩存的是本月今天之前的數(shù)據(jù)。
首先去配置文件 config/web.php 設(shè)置
// conf/web.php ... "cache" => [ "class" => "yiicachingFileCache", ], ...
采用默認(rèn)的就好,代碼進(jìn)行一點(diǎn)小手術(shù)(將今天之前的代碼多帶帶處理),核心邏輯不變。
$cache = Yii::$app->cache; $cacheKey = "month-report-{$m}"; $days = ""; $moneys = ""; // 今天之前的數(shù)據(jù),也是我們要緩存的數(shù)據(jù) $monthDatBeforeToday = $cache->get($cacheKey); if ($monthDatBeforeToday === false) { for($i = 1;$i < date("d",time());$i++){ $days .= $i.","; $begin_time = strtotime($y."-".$m."-".$i) + Yii::$app->params["business_hour"]["begin_time"]; $end_time = strtotime($y."-".$m."-".$i) + Yii::$app->params["business_hour"]["end_time"]; $money = Order::find() ->where([">","dish_id",0]) ->andWhere(["pay_state"=>"pay"]) ->andWhere([">=","pay_time",$begin_time]) ->andWhere(["<=","pay_time",$end_time]) ->andWhere(["store_id"=>Yii::$app->admin->identity->store_id]) ->sum("money"); $moneys .= ($money > 0 ? $money : 0).","; } $monthDatBeforeToday = ["days"=>$days,"moneys"=>$moneys]; $cache->set($cacheKey,$monthDatBeforeToday,7200); } $days = $monthDatBeforeToday["days"]; $moneys = $monthDatBeforeToday["moneys"]; for($i=date("d",time());$i<=$days_num; $i++){ $days .= $i.","; if($i > date("d",time())){ $moneys .= "0,"; continue; } $begin_time = strtotime($y."-".$m."-".$i) + Yii::$app->params["business_hour"]["begin_time"]; $end_time = strtotime($y."-".$m."-".$i) + Yii::$app->params["business_hour"]["end_time"]; $money = Order::find() ->where([">","dish_id",0]) ->andWhere(["pay_state"=>"pay"]) ->andWhere([">=","pay_time",$begin_time]) ->andWhere(["<=","pay_time",$end_time]) ->andWhere(["store_id"=>Yii::$app->admin->identity->store_id]) ->sum("money"); $moneys .= ($money > 0 ? $money : 0).","; }
當(dāng)然,從編寫上講,這段代碼可以繼續(xù)優(yōu)化,但是在原理上已經(jīng)完成了,我將今天之前的數(shù)據(jù)都緩存下來,今天的實(shí)時(shí)讀取,這樣就滿足了這個(gè)圖表和原來一樣的結(jié)果,為防止其他地方對(duì)訂單的修改,換成我2個(gè)小時(shí)更新一次。
用yii2-debug看看結(jié)果。
你沒看錯(cuò)數(shù)據(jù)庫從39次到10次,耗時(shí)從2.518秒到0.1秒
Action執(zhí)行從2.652秒減少到0.212秒
初步使用我們Yii2優(yōu)化三原則中的兩條,Action執(zhí)行提高了12倍、數(shù)據(jù)庫耗時(shí)減少了23倍。
優(yōu)化的步驟很簡(jiǎn)單:首先看能不能減少查詢次數(shù),如果不能就加速查詢,如果還不能就緩存結(jié)果。
記住它,一點(diǎn)點(diǎn)來,萬物均可優(yōu)化。
還有很多這僅僅是對(duì)統(tǒng)計(jì)數(shù)據(jù)采用緩存小試牛刀,如果對(duì)于訂單列表這種檢索那就要用到第二條原則了(如何讓查詢語句更快)。
下一篇將為你講解 對(duì)一個(gè)26萬數(shù)據(jù)的MYSQL表Yii2程序優(yōu)化實(shí)戰(zhàn)(真實(shí)例子)之二 【開刀數(shù)據(jù)表】
(完)
本文原創(chuàng)發(fā)布于微信公眾號(hào) 北哥小報(bào) , 嚴(yán)謹(jǐn)?shù)脑瓌?chuàng)技術(shù)文,還有一些其他研究。
文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請(qǐng)注明本文地址:http://www.ezyhdfw.cn/yun/61866.html
閱讀 3429·2023-04-26 00:57
閱讀 677·2021-10-08 10:05
閱讀 1423·2021-09-08 09:36
閱讀 4276·2021-08-12 13:31
閱讀 2630·2019-08-30 15:55
閱讀 2280·2019-08-30 15:55
閱讀 1086·2019-08-30 15:55
閱讀 2747·2019-08-29 13:17