本人對(duì)php不熟悉,現(xiàn)在采用PHP的magento開(kāi)源項(xiàng)目來(lái)做,在盡量少代碼修改的情況下讓頁(yè)面加載快些(期望日IP少于2,000,PV少于50,000,首頁(yè)打開(kāi)3s以內(nèi))。網(wǎng)站是運(yùn)行在Digital ocean的VPS(1GB 內(nèi)存,30GB SSD硬盤(pán))上的,不能做負(fù)載均衡。
安寧網(wǎng)站建設(shè)公司成都創(chuàng)新互聯(lián)公司,安寧網(wǎng)站設(shè)計(jì)制作,有大型網(wǎng)站制作公司豐富經(jīng)驗(yàn)。已為安寧上千多家提供企業(yè)網(wǎng)站建設(shè)服務(wù)。企業(yè)網(wǎng)站搭建\外貿(mào)網(wǎng)站制作要多少錢,請(qǐng)找那個(gè)售后服務(wù)好的安寧做網(wǎng)站的公司定做!
這個(gè)站的圖片比較多,也比較大,但總體數(shù)據(jù)量在10GB以下。在chrome下監(jiān)控了打開(kāi)速度,發(fā)現(xiàn)首頁(yè)文件等待時(shí)間達(dá)到了5s,而接收時(shí)間為幾百毫秒。另外一些靜態(tài)文件(JS,CSS很大,并且都在head內(nèi))也block住了其他頁(yè)面元素的下載和頁(yè)面渲染。所以需要對(duì)頁(yè)面和服務(wù)器同時(shí)進(jìn)行優(yōu)化。
我的想法是從以下幾個(gè)方面來(lái)做:
1.首先從架構(gòu)上使用lanmp(偏向這個(gè))或者lamp。
打算使用網(wǎng)上的一鍵安裝包,不太清楚這幾個(gè)之間最佳的版本組合是什么樣的(都用最新版本?)? 是自己?jiǎn)为?dú)編譯還是一鍵安裝好?
2.服務(wù)端優(yōu)化,主要使用緩存手段
1)Zend Optimizer優(yōu)化PHP
2)APC、eaccelerator或者XCache對(duì)PHP緩存以及最新出來(lái)的Opcache。哪個(gè)比較好?
3)Varnish配合Nginx進(jìn)行緩存靜態(tài)資源緩存。相對(duì)于squid,哪個(gè)比較好?
4)memcached進(jìn)行數(shù)據(jù)庫(kù)緩存
1-4項(xiàng)同時(shí)使用不知道會(huì)不會(huì)有沒(méi)有沖突?或者有沒(méi)有更好的方案。因?yàn)椴幌雽?duì)代碼進(jìn)行大改,所以服務(wù)端緩存最佳實(shí)踐這塊請(qǐng)重點(diǎn)給出意見(jiàn)。
3. 使用CDN加速靜態(tài)資源
4. 優(yōu)化靜態(tài)資源,使用minify來(lái)合并壓縮CSS,JS這些靜態(tài)資源
5. 啟用gzip
6. 對(duì)圖片和JS等靜態(tài)資源增加Expires頭,這條應(yīng)該算頁(yè)面優(yōu)化吧,放到后面來(lái)。
參考了一些資料后發(fā)現(xiàn)優(yōu)化方法有很多,用的太多方法(特別是緩存手段)隱患越大,有沒(méi)有優(yōu)化的最佳策略或者方法論(而不僅僅從工具上)?
關(guān)于mysql處理百萬(wàn)級(jí)以上的數(shù)據(jù)時(shí)如何提高其查詢速度的方法
最近一段時(shí)間由于工作需要,開(kāi)始關(guān)注針對(duì)Mysql數(shù)據(jù)庫(kù)的select查詢語(yǔ)句的相關(guān)優(yōu)化方法。
由于在參與的實(shí)際項(xiàng)目中發(fā)現(xiàn)當(dāng)mysql表的數(shù)據(jù)量達(dá)到百萬(wàn)級(jí)時(shí),普通SQL查詢效率呈直線下降,而且如果where中的查詢條件較多時(shí),其查詢速度簡(jiǎn)直無(wú)法容忍。曾經(jīng)測(cè)試對(duì)一個(gè)包含400多萬(wàn)條記錄(有索引)的表執(zhí)行一條條件查詢,其查詢時(shí)間竟然高達(dá)40幾秒,相信這么高的查詢延時(shí),任何用戶都會(huì)抓狂。因此如何提高sql語(yǔ)句查詢效率,顯得十分重要。以下是網(wǎng)上流傳比較廣泛的30種SQL查詢語(yǔ)句優(yōu)化方法:
1、應(yīng)盡量避免在 where 子句中使用!=或操作符,否則將引擎放棄使用索引而進(jìn)行全表掃描。
2、對(duì)查詢進(jìn)行優(yōu)化,應(yīng)盡量避免全表掃描,首先應(yīng)考慮在 where 及 order by 涉及的列上建立索引。
3、應(yīng)盡量避免在 where 子句中對(duì)字段進(jìn)行 null 值判斷,否則將導(dǎo)致引擎放棄使用索引而進(jìn)行全表掃描,如:
select id from t where num is null
可以在num上設(shè)置默認(rèn)值0,確保表中num列沒(méi)有null值,然后這樣查詢:
select id from t where num=0
4、盡量避免在 where 子句中使用 or 來(lái)連接條件,否則將導(dǎo)致引擎放棄使用索引而進(jìn)行全表掃描,如:
select id from t where num=10 or num=20
可以這樣查詢:
select id from t where num=10
union all
select id from t where num=20
5、下面的查詢也將導(dǎo)致全表掃描:(不能前置百分號(hào))
select id from t where name like ‘%c%’
若要提高效率,可以考慮全文檢索。
6、in 和 not in 也要慎用,否則會(huì)導(dǎo)致全表掃描,如:
select id from t where num in(1,2,3)
對(duì)于連續(xù)的數(shù)值,能用 between 就不要用 in 了:
select id from t where num between 1 and 3
7、如果在 where 子句中使用參數(shù),也會(huì)導(dǎo)致全表掃描。因?yàn)镾QL只有在運(yùn)行時(shí)才會(huì)解析局部變量,但優(yōu)化程序不能將訪問(wèn)計(jì)劃的選擇推遲到運(yùn)行時(shí);它必須在編譯時(shí)進(jìn)行選擇。然 而,如果在編譯時(shí)建立訪問(wèn)計(jì)劃,變量的值還是未知的,因而無(wú)法作為索引選擇的輸入項(xiàng)。如下面語(yǔ)句將進(jìn)行全表掃描:
select id from t where num=@num
可以改為強(qiáng)制查詢使用索引:
select id from t with(index(索引名)) where num=@num
8、應(yīng)盡量避免在 where 子句中對(duì)字段進(jìn)行表達(dá)式操作,這將導(dǎo)致引擎放棄使用索引而進(jìn)行全表掃描。如:
select id from t where num/2=100
應(yīng)改為:
select id from t where num=100*2
9、應(yīng)盡量避免在where子句中對(duì)字段進(jìn)行函數(shù)操作,這將導(dǎo)致引擎放棄使用索引而進(jìn)行全表掃描。如:
select id from t where substring(name,1,3)=’abc’–name以abc開(kāi)頭的id
select id from t where datediff(day,createdate,’2005-11-30′)=0–’2005-11-30′生成的id
應(yīng)改為:
select id from t where name like ‘a(chǎn)bc%’
select id from t where createdate=’2005-11-30′ and createdate’2005-12-1′
10、不要在 where 子句中的“=”左邊進(jìn)行函數(shù)、算術(shù)運(yùn)算或其他表達(dá)式運(yùn)算,否則系統(tǒng)將可能無(wú)法正確使用索引。
11、在使用索引字段作為條件時(shí),如果該索引是復(fù)合索引,那么必須使用到該索引中的第一個(gè)字段作為條件時(shí)才能保證系統(tǒng)使用該索引,否則該索引將不會(huì)被使 用,并且應(yīng)盡可能的讓字段順序與索引順序相一致。
12、不要寫(xiě)一些沒(méi)有意義的查詢,如需要生成一個(gè)空表結(jié)構(gòu):
select col1,col2 into #t from t where 1=0
這類代碼不會(huì)返回任何結(jié)果集,但是會(huì)消耗系統(tǒng)資源的,應(yīng)改成這樣:
create table #t(…)
13、很多時(shí)候用 exists 代替 in 是一個(gè)好的選擇:
select num from a where num in(select num from b)
用下面的語(yǔ)句替換:
select num from a where exists(select 1 from b where num=a.num)
14、并不是所有索引對(duì)查詢都有效,SQL是根據(jù)表中數(shù)據(jù)來(lái)進(jìn)行查詢優(yōu)化的,當(dāng)索引列有大量數(shù)據(jù)重復(fù)時(shí),SQL查詢可能不會(huì)去利用索引,如一表中有字段 sex,male、female幾乎各一半,那么即使在sex上建了索引也對(duì)查詢效率起不了作用。
15、索引并不是越多越好,索引固然可以提高相應(yīng)的 select 的效率,但同時(shí)也降低了 insert 及 update 的效率,因?yàn)?insert 或 update 時(shí)有可能會(huì)重建索引,所以怎樣建索引需要慎重考慮,視具體情況而定。一個(gè)表的索引數(shù)最好不要超過(guò)6個(gè),若太多則應(yīng)考慮一些不常使用到的列上建的索引是否有 必要。
16.應(yīng)盡可能的避免更新 clustered 索引數(shù)據(jù)列,因?yàn)?clustered 索引數(shù)據(jù)列的順序就是表記錄的物理存儲(chǔ)順序,一旦該列值改變將導(dǎo)致整個(gè)表記錄的順序的調(diào)整,會(huì)耗費(fèi)相當(dāng)大的資源。若應(yīng)用系統(tǒng)需要頻繁更新 clustered 索引數(shù)據(jù)列,那么需要考慮是否應(yīng)將該索引建為 clustered 索引。
17、盡量使用數(shù)字型字段,若只含數(shù)值信息的字段盡量不要設(shè)計(jì)為字符型,這會(huì)降低查詢和連接的性能,并會(huì)增加存儲(chǔ)開(kāi)銷。這是因?yàn)橐嬖谔幚聿樵兒瓦B接時(shí)會(huì) 逐個(gè)比較字符串中每一個(gè)字符,而對(duì)于數(shù)字型而言只需要比較一次就夠了。
18、盡可能的使用 varchar/nvarchar 代替 char/nchar ,因?yàn)槭紫茸冮L(zhǎng)字段存儲(chǔ)空間小,可以節(jié)省存儲(chǔ)空間,其次對(duì)于查詢來(lái)說(shuō),在一個(gè)相對(duì)較小的字段內(nèi)搜索效率顯然要高些。
19、任何地方都不要使用 select * from t ,用具體的字段列表代替“*”,不要返回用不到的任何字段。
20、盡量使用表變量來(lái)代替臨時(shí)表。如果表變量包含大量數(shù)據(jù),請(qǐng)注意索引非常有限(只有主鍵索引)。
21、避免頻繁創(chuàng)建和刪除臨時(shí)表,以減少系統(tǒng)表資源的消耗。
22、臨時(shí)表并不是不可使用,適當(dāng)?shù)厥褂盟鼈兛梢允鼓承├谈行?,例如,?dāng)需要重復(fù)引用大型表或常用表中的某個(gè)數(shù)據(jù)集時(shí)。但是,對(duì)于一次性事件,最好使 用導(dǎo)出表。
23、在新建臨時(shí)表時(shí),如果一次性插入數(shù)據(jù)量很大,那么可以使用 select into 代替 create table,避免造成大量 log ,以提高速度;如果數(shù)據(jù)量不大,為了緩和系統(tǒng)表的資源,應(yīng)先create table,然后insert。
24、如果使用到了臨時(shí)表,在存儲(chǔ)過(guò)程的最后務(wù)必將所有的臨時(shí)表顯式刪除,先 truncate table ,然后 drop table ,這樣可以避免系統(tǒng)表的較長(zhǎng)時(shí)間鎖定。
25、盡量避免使用游標(biāo),因?yàn)橛螛?biāo)的效率較差,如果游標(biāo)操作的數(shù)據(jù)超過(guò)1萬(wàn)行,那么就應(yīng)該考慮改寫(xiě)。
26、使用基于游標(biāo)的方法或臨時(shí)表方法之前,應(yīng)先尋找基于集的解決方案來(lái)解決問(wèn)題,基于集的方法通常更有效。
27、與臨時(shí)表一樣,游標(biāo)并不是不可使用。對(duì)小型數(shù)據(jù)集使用 FAST_FORWARD 游標(biāo)通常要優(yōu)于其他逐行處理方法,尤其是在必須引用幾個(gè)表才能獲得所需的數(shù)據(jù)時(shí)。在結(jié)果集中包括“合計(jì)”的例程通常要比使用游標(biāo)執(zhí)行的速度快。如果開(kāi)發(fā)時(shí) 間允許,基于游標(biāo)的方法和基于集的方法都可以嘗試一下,看哪一種方法的效果更好。
28、在所有的存儲(chǔ)過(guò)程和觸發(fā)器的開(kāi)始處設(shè)置 SET NOCOUNT ON ,在結(jié)束時(shí)設(shè)置 SET NOCOUNT OFF 。無(wú)需在執(zhí)行存儲(chǔ)過(guò)程和觸發(fā)器的每個(gè)語(yǔ)句后向客戶端發(fā)送 DONE_IN_PROC 消息。
29、盡量避免向客戶端返回大數(shù)據(jù)量,若數(shù)據(jù)量過(guò)大,應(yīng)該考慮相應(yīng)需求是否合理。
30、盡量避免大事務(wù)操作,提高系統(tǒng)并發(fā)能力。
php+Mysql 優(yōu)化,百萬(wàn)至千萬(wàn)級(jí)快速分頁(yè)
MySql 性能到底能有多高?用了php半年多,真正如此深入的去思考這個(gè)問(wèn)題還是從前天開(kāi)始。有過(guò)痛苦有過(guò)絕望,到現(xiàn)在充滿信心!MySql 這個(gè)數(shù)據(jù)庫(kù)絕對(duì)是適合dba級(jí)的高手去玩的,一般做一點(diǎn)1萬(wàn)篇新聞的小型系統(tǒng)怎么寫(xiě)都可以,用xx框架可以實(shí)現(xiàn)快速開(kāi)發(fā)??墒菙?shù)據(jù)量到了10萬(wàn),百萬(wàn)至千萬(wàn),他的性能還能那么高嗎?一點(diǎn)小小的失誤,可能造成整個(gè)系統(tǒng)的改寫(xiě),甚至更本系統(tǒng)無(wú)法正常運(yùn)行!好了,不那么多廢話了。用事實(shí)說(shuō)話,看例子:
數(shù)據(jù)表 collect ( id, title ,info ,vtype) 就這4個(gè)字段,其中 title 用定長(zhǎng),info 用text, id 是逐漸,vtype是tinyint,vtype是索引。這是一個(gè)基本的新聞系統(tǒng)的簡(jiǎn)單模型?,F(xiàn)在往里面填充數(shù)據(jù),填充10萬(wàn)篇新聞。
最后collect 為 10萬(wàn)條記錄,數(shù)據(jù)庫(kù)表占用硬盤(pán)1.6G。OK ,看下面這條sql語(yǔ)句:
select id,title from collect limit 1000,10; 很快;基本上0.01秒就OK,再看下面的
select id,title from collect limit 90000,10; 從9萬(wàn)條開(kāi)始分頁(yè),結(jié)果?
8-9秒完成,my god 哪出問(wèn)題了????其實(shí)要優(yōu)化這條數(shù)據(jù),網(wǎng)上找得到答案。看下面一條語(yǔ)句:
select id from collect order by id limit 90000,10; 很快,0.04秒就OK。為什么?因?yàn)橛昧薸d主鍵做索引當(dāng)然快。網(wǎng)上的改法是:
select id,title from collect where id=(select id from collect order by id limit 90000,1) limit 10;
這就是用了id做索引的結(jié)果??墒菃?wèn)題復(fù)雜那么一點(diǎn)點(diǎn),就完了??聪旅娴恼Z(yǔ)句
select id from collect where vtype=1 order by id limit 90000,10; 很慢,用了8-9秒!
到了這里我相信很多人會(huì)和我一樣,有崩潰感覺(jué)!vtype 做了索引了啊?怎么會(huì)慢呢?vtype做了索引是不錯(cuò),你直接 select id from collect where vtype=1 limit 1000,10; 是很快的,基本上0.05秒,可是提高90倍,從9萬(wàn)開(kāi)始,那就是0.05*90=4.5秒的速度了。和測(cè)試結(jié)果8-9秒到了一個(gè)數(shù)量級(jí)。從這里開(kāi)始有人提出了分表的思路,這個(gè)和discuz 論壇是一樣的思路。思路如下:
建一個(gè)索引表: t (id,title,vtype) 并設(shè)置成定長(zhǎng),然后做分頁(yè),分頁(yè)出結(jié)果再到 collect 里面去找info 。 是否可行呢?實(shí)驗(yàn)下就知道了。
10萬(wàn)條記錄到 t(id,title,vtype) 里,數(shù)據(jù)表大小20M左右。用
select id from t where vtype=1 order by id limit 90000,10; 很快了?;旧?.1-0.2秒可以跑完。為什么會(huì)這樣呢?我猜想是因?yàn)閏ollect 數(shù)據(jù)太多,所以分頁(yè)要跑很長(zhǎng)的路。limit 完全和數(shù)據(jù)表的大小有關(guān)的。其實(shí)這樣做還是全表掃描,只是因?yàn)閿?shù)據(jù)量小,只有10萬(wàn)才快。OK,來(lái)個(gè)瘋狂的實(shí)驗(yàn),加到100萬(wàn)條,測(cè)試性能。
加了10倍的數(shù)據(jù),馬上t表就到了200多M,而且是定長(zhǎng)。還是剛才的查詢語(yǔ)句,時(shí)間是0.1-0.2秒完成!分表性能沒(méi)問(wèn)題?錯(cuò)!因?yàn)槲覀兊膌imit還是9萬(wàn),所以快。給個(gè)大的,90萬(wàn)開(kāi)始
select id from t where vtype=1 order by id limit 900000,10; 看看結(jié)果,時(shí)間是1-2秒!
why 分表了時(shí)間還是這么長(zhǎng),非常之郁悶!有人說(shuō)定長(zhǎng)會(huì)提高limit的性能,開(kāi)始我也以為,因?yàn)橐粭l記錄的長(zhǎng)度是固定的,mysql 應(yīng)該可以算出90萬(wàn)的位置才對(duì)??? 可是我們高估了mysql 的智能,他不是商務(wù)數(shù)據(jù)庫(kù),事實(shí)證明定長(zhǎng)和非定長(zhǎng)對(duì)limit影響不大?怪不得有人說(shuō) discuz到了100萬(wàn)條記錄就會(huì)很慢,我相信這是真的,這個(gè)和數(shù)據(jù)庫(kù)設(shè)計(jì)有關(guān)!
難道MySQL 無(wú)法突破100萬(wàn)的限制嗎???到了100萬(wàn)的分頁(yè)就真的到了極限???
答案是: NO !!!! 為什么突破不了100萬(wàn)是因?yàn)椴粫?huì)設(shè)計(jì)mysql造成的。下面介紹非分表法,來(lái)個(gè)瘋狂的測(cè)試!一張表搞定100萬(wàn)記錄,并且10G 數(shù)據(jù)庫(kù),如何快速分頁(yè)!
好了,我們的測(cè)試又回到 collect表,開(kāi)始測(cè)試結(jié)論是: 30萬(wàn)數(shù)據(jù),用分表法可行,超過(guò)30萬(wàn)他的速度會(huì)慢道你無(wú)法忍受!當(dāng)然如果用分表+我這種方法,那是絕對(duì)完美的。但是用了我這種方法后,不用分表也可以完美解決!
答案就是:復(fù)合索引!有一次設(shè)計(jì)mysql索引的時(shí)候,無(wú)意中發(fā)現(xiàn)索引名字可以任取,可以選擇幾個(gè)字段進(jìn)來(lái),這有什么用呢?開(kāi)始的select id from collect order by id limit 90000,10; 這么快就是因?yàn)樽吡怂饕?,可是如果加了where 就不走索引了。抱著試試看的想法加了 search(vtype,id) 這樣的索引。然后測(cè)試
select id from collect where vtype=1 limit 90000,10; 非???!0.04秒完成!
再測(cè)試: select id ,title from collect where vtype=1 limit 90000,10; 非常遺憾,8-9秒,沒(méi)走search索引!
再測(cè)試:search(id,vtype),還是select id 這個(gè)語(yǔ)句,也非常遺憾,0.5秒。
綜上:如果對(duì)于有where 條件,又想走索引用limit的,必須設(shè)計(jì)一個(gè)索引,將where 放第一位,limit用到的主鍵放第2位,而且只能select 主鍵!
完美解決了分頁(yè)問(wèn)題了??梢钥焖俜祷豬d就有希望優(yōu)化limit , 按這樣的邏輯,百萬(wàn)級(jí)的limit 應(yīng)該在0.0x秒就可以分完??磥?lái)mysql 語(yǔ)句的優(yōu)化和索引時(shí)非常重要的!
好了,回到原題,如何將上面的研究成功快速應(yīng)用于開(kāi)發(fā)呢?如果用復(fù)合查詢,我的輕量級(jí)框架就沒(méi)的用了。分頁(yè)字符串還得自己寫(xiě),那多麻煩?這里再看一個(gè)例子,思路就出來(lái)了:
select * from collect where id in (9000,12,50,7000); 竟然 0秒就可以查完!
mygod ,mysql 的索引竟然對(duì)于in語(yǔ)句同樣有效!看來(lái)網(wǎng)上說(shuō)in無(wú)法用索引是錯(cuò)誤的!
有了這個(gè)結(jié)論,就可以很簡(jiǎn)單的應(yīng)用于輕量級(jí)框架了:
代碼如下:
$db=dblink();
$db-pagesize=20;
$sql="select id from collect where vtype=$vtype";
$db-execute($sql);
$strpage=$db-strpage(); //將分頁(yè)字符串保存在臨時(shí)變量,方便輸出
while($rs=$db-fetch_array()){
$strid.=$rs['id'].',';
}
$strid=substr($strid,0,strlen($strid)-1); //構(gòu)造出id字符串
$db-pagesize=0; //很關(guān)鍵,在不注銷類的情況下,將分頁(yè)清空,這樣只需要用一次數(shù)據(jù)庫(kù)連接,不需要再開(kāi);
$db-execute("select id,title,url,sTime,gTime,vtype,tag from collect where id in ($strid)");
php while($rs=$db-fetch_array()):
tr
td$amp;amp;$amp;nbsp; php echo $rs['id']; $amp;amp;$lt;/td
td$amp;amp;$amp;nbsp; php echo $rs['url']; $amp;amp;$lt;/td
td$amp;amp;$amp;nbsp; php echo $rs['sTime']; $amp;amp;$lt;/td
td$amp;amp;$amp;nbsp; php echo $rs['gTime']; $amp;amp;$lt;/td
td$amp;amp;$amp;nbsp; php echo $rs['vtype']; $amp;amp;$lt;/td
td$amp;amp;$amp;nbsp;a act=showid= php echo $rs['id']; $amp;quot;$ target="_blank"$amp;amp;$lt; php echo $rs['title']; $amp;amp;$lt;/a$amp;amp;$lt;/td
td$amp;amp;$amp;nbsp; php echo $rs['tag']; $amp;amp;$lt;/td
/tr
php endwhile;
/table
php
echo $strpage;
通過(guò)簡(jiǎn)單的變換,其實(shí)思路很簡(jiǎn)單:1)通過(guò)優(yōu)化索引,找出id,并拼成 "123,90000,12000" 這樣的字符串。2)第2次查詢找出結(jié)果。
小小的索引+一點(diǎn)點(diǎn)的改動(dòng)就使mysql 可以支持百萬(wàn)甚至千萬(wàn)級(jí)的高效分頁(yè)!
通過(guò)這里的例子,我反思了一點(diǎn):對(duì)于大型系統(tǒng),PHP千萬(wàn)不能用框架,尤其是那種連sql語(yǔ)句都看不到的框架!因?yàn)殚_(kāi)始對(duì)于我的輕量級(jí)框架都差點(diǎn)崩潰!只適合小型應(yīng)用的快速開(kāi)發(fā),對(duì)于ERP,OA,大型網(wǎng)站,數(shù)據(jù)層包括邏輯層的東西都不能用框架。如果程序員失去了對(duì)sql語(yǔ)句的把控,那項(xiàng)目的風(fēng)險(xiǎn)將會(huì)成幾何級(jí)數(shù)增加!尤其是用mysql 的時(shí)候,mysql 一定需要專業(yè)的dba 才可以發(fā)揮他的最佳性能。一個(gè)索引所造成的性能差別可能是上千倍!
PS: 經(jīng)過(guò)實(shí)際測(cè)試,到了100萬(wàn)的數(shù)據(jù),160萬(wàn)數(shù)據(jù),15G表,190M索引,就算走索引,limit都得0.49秒。所以分頁(yè)最好別讓別人看到10萬(wàn)條以后的數(shù)據(jù),要不然會(huì)很慢!就算用索引。經(jīng)過(guò)這樣的優(yōu)化,mysql到了百萬(wàn)級(jí)分頁(yè)是個(gè)極限!但有這樣的成績(jī)已經(jīng)很不錯(cuò),如果你是用sqlserver肯定卡死!而 160萬(wàn)的數(shù)據(jù)用 id in (str) 很快,基本還是0秒。如果這樣,千萬(wàn)級(jí)的數(shù)據(jù),mysql應(yīng)該也很容易應(yīng)付。
架構(gòu)優(yōu)化涉及到技術(shù)、存儲(chǔ)、網(wǎng)絡(luò)、服務(wù)的選型和構(gòu)架,盡量使用成熟和現(xiàn)代的開(kāi)發(fā)架構(gòu)和設(shè)計(jì)模式。前后端完全分離設(shè)計(jì),便于前后端的獨(dú)立優(yōu)化,也更加便于測(cè)試工作。
如果你的應(yīng)用遇到了性能瓶頸,這個(gè)時(shí)候要考慮的就是優(yōu)化架構(gòu)而不是優(yōu)化代碼本身,因?yàn)榧軜?gòu)層面的優(yōu)化效果往往是最顯著的。
架構(gòu)的優(yōu)化需要根據(jù)自身運(yùn)營(yíng)情況來(lái)調(diào)整,切忌不可按圖索驥提前優(yōu)化,反而容易得不償失,導(dǎo)致技術(shù)成本提高甚至“負(fù)優(yōu)化”
部署環(huán)境千萬(wàn)不要忘記關(guān)閉調(diào)試模式,這不僅僅是出于性能考慮,更多是基于安全因素。事實(shí)上,建議通過(guò)環(huán)境變量來(lái)配置關(guān)閉調(diào)試模式,這樣部署后不需要更改任何配置文件。
因?yàn)檎{(diào)試模式影響日志記錄信息、額外的調(diào)試信息和緩存失效,關(guān)閉調(diào)試模式能夠帶來(lái)一定的性能提升
使用多模塊功能會(huì)增加文件的 I/O 開(kāi)銷和額外的配置及檢查,如非必要在規(guī)劃你的應(yīng)用架構(gòu)的時(shí)候盡量考慮使用單一模塊,然后使用控制器分級(jí)來(lái)解決控制器過(guò)多的問(wèn)題。
使用單一模塊的性能優(yōu)勢(shì),在部署到 swoole 的時(shí)候可以得到更加充分的體現(xiàn),因?yàn)閼?yīng)用文件一旦啟動(dòng)服務(wù),就會(huì)載入內(nèi)存,而模塊的相關(guān)文件則會(huì)每次請(qǐng)求重新加載。
在定義路由規(guī)則的時(shí)候,不要使用數(shù)組方式,盡量使用方法注冊(cè)路由,并且多使用路由分組(或者資源路由)。分組路由可以減少路由的匹配次數(shù),從而提升路由性能。如果你有多個(gè)域名的不同路由,也要按域名規(guī)劃使用路由。
盡可能設(shè)計(jì)在路由中進(jìn)行當(dāng)前路由的數(shù)據(jù)驗(yàn)證和權(quán)限檢查等操作,一方面比較清晰,另外一方面可以盡量把驗(yàn)證操作提前,而不必等到控制器執(zhí)行。
在分組比較多的情況下,開(kāi)啟路由的延遲解析。
如果同一個(gè)分組下面有比較多的路由規(guī)則,建議合并路由規(guī)則
對(duì)于 GET 請(qǐng)求的路由,可以設(shè)置路由的請(qǐng)求緩存。
部署階段,可以開(kāi)啟路由緩存。
首先保持良好的開(kāi)發(fā)習(xí)慣,了解 Db類和模型的正確使用姿勢(shì) ,數(shù)據(jù)庫(kù)本身的性能優(yōu)化可以參考 MySQL性能優(yōu)化的最佳21條經(jīng)驗(yàn) ,下面主要是對(duì)框架中數(shù)據(jù)查詢相關(guān)的優(yōu)化策略。
盡量減少每次請(qǐng)求的查詢次數(shù),并對(duì)實(shí)時(shí)性要求不高的數(shù)據(jù)查詢合理規(guī)劃數(shù)據(jù)查詢緩存(優(yōu)先考慮使用 Redis 緩存)
如果使用了關(guān)聯(lián)查詢, cache 方法只能用于主模型的數(shù)據(jù)緩存,但你可以使用 Cache 類的 remember 方法進(jìn)行方便的數(shù)據(jù)緩存。
盡量減少查詢次數(shù)是出于性能考慮,但不是必須,使用最少的查詢不代表性能就一定是最高。一個(gè)復(fù)雜的 JOIN 查詢性能不見(jiàn)得有兩次簡(jiǎn)單的查詢高,而使用簡(jiǎn)單的查詢反而更清晰易懂,并且更方便進(jìn)行數(shù)據(jù)查詢緩存。
不要總是以為模型的性能一定比 Db 類低,框架的ORM查詢?cè)O(shè)計(jì)經(jīng)過(guò)了較為合理的優(yōu)化,正確使用模型一樣可以有出色的性能,而且比 Db 查詢要方便很多。
尤其是對(duì)于一些復(fù)雜的設(shè)計(jì)來(lái)說(shuō)使用模型關(guān)聯(lián)顯得比直接用Db更加簡(jiǎn)單,例如使用關(guān)聯(lián)預(yù)載入查詢就可以避免 N+1 查詢問(wèn)題。
如果用 Db 類自己實(shí)現(xiàn)的話,費(fèi)時(shí)費(fèi)力,性能還不一定優(yōu)。
對(duì)于內(nèi)存開(kāi)銷比較大的應(yīng)用,在做大量數(shù)據(jù)查詢和處理的時(shí)候,使用 cursor 方法,可以利用PHP的生成器特性,減少內(nèi)存占用。
你會(huì)發(fā)現(xiàn)用戶數(shù)據(jù)不論是1萬(wàn)還是10萬(wàn)級(jí)別,內(nèi)存開(kāi)銷并沒(méi)有大的變化。
涉及到對(duì)大量數(shù)據(jù)的處理,包括數(shù)據(jù)遷移、批量更新,盡量使用命令行指令運(yùn)行,否則會(huì)因?yàn)槌瑫r(shí)而中斷
可以通過(guò)數(shù)據(jù)集的方法完成的子集或者排序操作不要再次查詢,例如:
利用下面指令在部署后生成字段緩存,可以減少每次數(shù)據(jù)表的字段查詢開(kāi)銷。
注意:一旦數(shù)據(jù)庫(kù)的表結(jié)構(gòu)發(fā)生變化,必須重新生成。
每次在應(yīng)用初始化或者模塊初始化的時(shí)候會(huì)有一定的 I/O 開(kāi)銷,如果已經(jīng)開(kāi)啟 OpCache 的話對(duì)性能影響甚微,如果比較在意的也可以通過(guò)命令行指令生成配置緩存(包括相關(guān)的公共文件和各種定義文件)。
生成應(yīng)用配置緩存:
生成模塊配置緩存:
注意:一旦配置或者公共文件發(fā)生變化,必須重新生成。
類庫(kù)映射可以提升類庫(kù)的自動(dòng)加載性能,使用下面的指令可以生成系統(tǒng)類庫(kù)和應(yīng)用類庫(kù)的類庫(kù)映射(包括 extend 目錄下的類庫(kù))。
vendor 目錄下的類庫(kù)可以使用 composer 的 dump-autoload 指令優(yōu)化加載性能。
該命令把 PSR-0 和 PSR-4 轉(zhuǎn)換為一個(gè)類映射表,來(lái)提高類的加載速度。
當(dāng)前名稱:php中數(shù)據(jù)庫(kù)性能優(yōu)化 php sql優(yōu)化
文章分享:http://chinadenli.net/article6/dodisig.html
成都網(wǎng)站建設(shè)公司_創(chuàng)新互聯(lián),為您提供標(biāo)簽優(yōu)化、品牌網(wǎng)站建設(shè)、網(wǎng)站設(shè)計(jì)公司、定制網(wǎng)站、微信小程序、網(wǎng)站導(dǎo)航
聲明:本網(wǎng)站發(fā)布的內(nèi)容(圖片、視頻和文字)以用戶投稿、用戶轉(zhuǎn)載內(nèi)容為主,如果涉及侵權(quán)請(qǐng)盡快告知,我們將會(huì)在第一時(shí)間刪除。文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如需處理請(qǐng)聯(lián)系客服。電話:028-86922220;郵箱:631063699@qq.com。內(nèi)容未經(jīng)允許不得轉(zhuǎn)載,或轉(zhuǎn)載時(shí)需注明來(lái)源: 創(chuàng)新互聯(lián)