轉(zhuǎn)帖|其它|編輯:郝浩|2011-05-27 15:23:52.000|閱讀 392 次
概述:這一系列文章我計劃花三個大的方向來講解一些性能方面的東西,包括數(shù)據(jù)庫性能優(yōu)化、asp.net程序優(yōu)化和前端優(yōu)化,這里我將數(shù)據(jù)庫性能優(yōu)化放在前面,代表了它的重要性。我個人認(rèn)為影響一個網(wǎng)站性能從程序上來說最主要就是這三個方面,從這三個方面逐一進行優(yōu)化,將對網(wǎng)站性能的提升會有較大的幫助。
# 界面/圖表報表/文檔/IDE等千款熱門軟控件火熱銷售中 >>
相信園子里有不少程序員同學(xué)都是在做著xx管理系統(tǒng)這樣的中小型項目,這種項目往往是一種工作量的代碼,程序員同學(xué)就將青年耗費在這樣的項目中,不斷改變需求,不斷地加班趕工,于是就開始懷疑這個行業(yè),對developer充滿厭惡,想學(xué)新東西,可是周圍同事的水平都是差不多;想買書學(xué)平時加班根本沒有自己的時間。這種狀況相信大多數(shù)情況都在我們身邊發(fā)生,我之前就是處于這種狀態(tài),使用的是asp.net語言,不過很難界定所做的項目是網(wǎng)站還是軟件,因為它很復(fù)雜,開發(fā)周期和傳統(tǒng)軟件開發(fā)沒有什么區(qū)別,但它確實是部署在IIS上可以通過瀏覽器訪問。或者又是專門給企業(yè)做網(wǎng)站的程序員,一套程序內(nèi)核不變,只是每個網(wǎng)站換個殼,新聞系統(tǒng)、留言系統(tǒng)、下載系統(tǒng)等等。……為什么我要說這些呢?因為在前面我要說的是,這些并不是真正的互聯(lián)網(wǎng)公司,這種公司往往追求利益最大化、最快化、最直接化,簽單給錢,整個流程程序員的作用幾乎可以忽略不計,因為隨便招幾個畢業(yè)生帶幾一兩個月就可以繼續(xù)把項目做下去。
而在互聯(lián)網(wǎng)公司里,尤其是中大型網(wǎng)站,性能絕對是躍居非常重要的位置,試想一下日IP過百萬上千萬,并發(fā)成千上萬的網(wǎng)站,如果金喜正規(guī)買球每節(jié)省1k的流量,那么一天下來就為企業(yè)節(jié)省相當(dāng)可觀的支出;頁面加載每減少1秒的時間,就會減少可觀的用戶流失。我之前是在上段說講到的小公司做項目,現(xiàn)在在一家算是中型互聯(lián)網(wǎng)公司里,日PV幾十萬的網(wǎng)站,前端、代碼、數(shù)據(jù)庫設(shè)計的影響對網(wǎng)站的影響是如此之重大,是我之前從沒有親身體會到的。在這近一年的時間里,總結(jié)了一些關(guān)于asp.net性能優(yōu)化的一些經(jīng)驗與大家分享,由于個人水平的限制,難免有一些不準(zhǔn)確、不完善的地方,歡迎大家拍磚o(∩_∩)o
這一系列文章我計劃花三個大的方向來講解一些性能方面的東西,包括數(shù)據(jù)庫性能優(yōu)化、asp.net程序優(yōu)化和前端優(yōu)化,這里我將數(shù)據(jù)庫性能優(yōu)化放在前面,代表了它的重要性。我個人認(rèn)為影響一個網(wǎng)站性能從程序上來說最主要就是這三個方面,從這三個方面逐一進行優(yōu)化,將對網(wǎng)站性能的提升會有較大的幫助。
數(shù)據(jù)庫性能優(yōu)化
一、字段的建立
1、減少跨表查詢
需求確定后往往就開始建立數(shù)據(jù)庫,那么建立數(shù)據(jù)庫,對數(shù)據(jù)庫的操作離不開增刪改查這些最基本的操作,其中查詢應(yīng)該是頻繁的操作,提升查詢操作的一個基本的原則是盡量減少跨表查詢,也就是JOIN、UNION和子查詢等,這種情況往往最為常見,往往是A表中其中一個字段是B表的外鍵,查詢時往往需要同時將A表中的數(shù)據(jù)全部查詢出來,同時再把匹配A表外鍵的字段查詢出來,這樣就會大大增加查詢的成本。這里我們以文章系統(tǒng)為例,一般表結(jié)構(gòu)如下:
News(NewsId,NewsTitle,Content,CateId,PostUserId,Hits,AddTime)--文章 |
NewsCate(CateId,CateTitle)--文章分類 |
這樣的表結(jié)構(gòu)肯定就需要使用兩次查詢或者連接查詢等方法來取得兩張表的數(shù)據(jù)。如果統(tǒng)計一個分類下的文章數(shù)量,還需要SELECT COUNT(*)來進行News表的全表掃描來完成,這樣就會在性能上受到嚴(yán)重影響。
對于這種本身表結(jié)構(gòu)設(shè)計欠合理的情況,優(yōu)化SQL語句基本作用不大,改進方法是將表中需要跨表查詢的地方減少到最小,可以將表結(jié)構(gòu)建立如下:
News(NewsId,NewsTitle,Content,CateId,CateName, PostUserId,PostUserName,Hits,AddTime) |
NewsCate(CateId,CateTitle,NewsNum) |
這里進行了兩個地方的改進,一是將CateName同時并入到News表中,這樣可以避免跨表連接查詢帶來的性能損耗(PostUserName與此類似);二是將News表中的總記錄數(shù)存入NewsCate表中的NewsNum字段中,可以避免SELECT COUNT(*)帶來的性能損耗(在大數(shù)據(jù)量的情況下效果是非常明顯的)。由此產(chǎn)生的冗余字段帶來的性能影響與之前的性能影響相比較,可以很明顯的對比出來。這種優(yōu)化可以稱為以空間換時間。
2、排序問題
另外一點是針對AddTime字段,一般情況下以它排序的情況較多,這種DateTime類型字段在排序時會進行計算,它的排序比Int類型要慢得多,因此還可以考慮新增加一個DateNum(int)字段來儲存日期,比如AddTime為2011-05-27,那么插入到DateNum可以是20110527這個數(shù)字,這樣在排序時可以通過ORDER BY DateNum DESC來減少排序的時間。當(dāng)然如果你的AddTime默認(rèn)是getdate(),并且排序只有一個按時間排序的話,可以O(shè)RDER BY NewsID DESC來完成。
對于排序,數(shù)據(jù)庫在查詢出滿足WHERE所有條件的數(shù)據(jù)后,然后再進行排序,因此如果沒有必要,不要使用復(fù)雜的排序,可以根據(jù)實際情況考慮是否添加OrderNum來減少相關(guān)的排序;對于的確需要復(fù)雜的排序我們第二點會講到索引問題來解決。
3、需要外鍵嗎?
如果你的數(shù)據(jù)庫學(xué)得不錯的話,一定記得數(shù)據(jù)庫范式,滿足三級范式才是標(biāo)準(zhǔn)的數(shù)據(jù)庫設(shè)計,在實際情況中,絕不可完全照書本來。對于是否需要外鍵爭論一直較多,我的理解是外鍵是一個約束,它在避免程序插入異常數(shù)據(jù)會有一定的幫助,異常的數(shù)據(jù)會導(dǎo)致程序需要異常處理的地方增加,隨之代碼增加,程序穩(wěn)定性降低。但在實際的開發(fā)中,外鍵會導(dǎo)致調(diào)試程序的復(fù)雜,并且會在一定程序上降低SQL執(zhí)行的效率,因為數(shù)據(jù)在插入前引擎會對數(shù)據(jù)的合法性進行校驗,這樣在一定程序上也會降低數(shù)據(jù)庫的性能,另外對于外鍵數(shù)據(jù)在刪除情況下查詢主表數(shù)據(jù)可能會發(fā)生不可預(yù)料的異常。在網(wǎng)站中我的個人建議是不用外鍵,但為了避免出現(xiàn)DBNull的情況,“是否為空”這個選項在必要時要選擇不允許為空。
二、索引的建立
在項目開始前要確定實際項目中可能哪些會頻繁進行查詢——一般情況下實際情況是程序員和DBA是同一個人,因此假設(shè)你已經(jīng)知道了這些會頻繁查詢的地方。以一個文章系統(tǒng)為例來說,可能會有時間、分類和關(guān)鍵字這幾種查詢比較頻繁。那么必要時要建立索引,一般情況需要對其各自建立索引,比如實際的表結(jié)構(gòu)如下:
News(NewsId,NewsTitle,Content,CateId,CateName,PostUserId, PostUserName,Hits,AddTime,CommentNum) |
假設(shè)以分類和時間排序來進行查詢十分頻繁,那么需要各自建立CateId和AddTime索引;如果這個查詢屬于復(fù)雜查詢,如果SQL語句如下:
SELECT * FROM News WHERE CateId= 1 ORDER BY AddTime DESC,CommentNum DESC |
那么可以建立多個字段的復(fù)合索引,這里可以將CateId,AddTime建立復(fù)合索引,如有必要可以將CommentNum也包括在內(nèi)。
對于搜索如果以關(guān)鍵字查詢較為頻繁,建議在查詢字段上建立全文索引,全文索引是SQL Server內(nèi)置的搜索算法來進行的查詢規(guī)則,性能比LIKE就好很多。比如查詢標(biāo)題:
SELECT TOP 10 * FROM News WHERE CONTAINS(News,‘walkingp’) |
*注意SQL 2000及以后的版本才有全文索引功能。
三、查詢的優(yōu)化
查詢是絕大多數(shù)SQL語句優(yōu)化的用武之地,不同的SQL語句可能會讓查詢時間有著很大的區(qū)別;查詢優(yōu)化最核心的內(nèi)容就是減少scan,盡量做到seek;scan代表全表掃描,seek代表定位到某一行。使用COUNT、NOT、!=、IN、LIKE等都會引起全表掃描,如果這張表數(shù)據(jù)足夠多,那么性能影響是非常大的。更好的方法是避免這種全表掃描,使用最準(zhǔn)確的條件限制來縮小數(shù)據(jù)庫掃描的范圍,減少SQL執(zhí)行的時間。
以上表為例,ASP.NET程序最常使用的DAL功能是根據(jù)某一編號取數(shù)據(jù)然后存儲到對象中。
SELECT * FROM News WHERE NewsId=@NewsId |
這樣即使在查詢到需要的數(shù)據(jù)后,它仍會執(zhí)行剩余數(shù)據(jù)的查詢進行全表掃描,這樣就浪費了大量的資源和程序時間。可以使用TOP 1來進行條件限制:
SELECT TOP 1 * FROM News WHERE NewsId=@NewsId |
假設(shè)有一百萬條數(shù)據(jù),實際中NewsId=1,那么我們就節(jié)約了查詢999999條數(shù)據(jù)的時間。
一般情況下News表會很大,而NewsCate會很少,對于這種對比非常懸殊的兩表,如果進行連接查詢,將數(shù)據(jù)小的NewsCate放到JOIN后面,這樣可以提升查詢性能。
關(guān)于查詢優(yōu)化,相關(guān)的資料非常豐富,大家可以自己去搜索一下,對于爭執(zhí)比較多的類似IN和EXISTS等問題,可以在實際數(shù)據(jù)庫中測試其性能,然后決定選用哪一種。
四、SQL Profiler的使用
SQL Profiler是最容易被忽視的工具,而這個工具是數(shù)據(jù)庫性能優(yōu)化一個非常強大的工具,它與Management Studio在SQL Server安裝時都會綁定在一起,選擇新建跟蹤,然后在跟蹤屬性中選擇相應(yīng)的事件列,一般選擇CPU、Reads、Writes、Duration、StartTime、EndTime即可,它們對應(yīng)了在物理上SQL語句對CPU的占用、對硬盤讀寫的次數(shù)和起止時間,通過它可以很直觀地看出影響SQL性能的地方。
比如我這里測試是對一百萬條數(shù)據(jù)SELECT *和SELECT NewsId的性能測試,可以較直觀地看出SELECT * 在CPU損耗、和硬盤讀取上會大很多。因此在實際項目中建議“吃多少,拿多少”。
本站文章除注明轉(zhuǎn)載外,均為本站原創(chuàng)或翻譯。歡迎任何形式的轉(zhuǎn)載,但請務(wù)必注明出處、不得修改原文相關(guān)鏈接,如果存在內(nèi)容上的異議請郵件反饋至chenjj@fc6vip.cn
文章轉(zhuǎn)載自:博客園