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