程式|技巧|效能|最佳化
ASP 能快速執行你的動態網頁,但你還可以通過緊縮代碼和資料庫連接以使它們執行更快。這是一篇關於怎樣精簡代碼和Asp 特徵以獲得最快執行速度的詳細文章。對於一個急燥的使用者來說,任何在按下使用者按鈕到結果出現在它們的螢幕之間的延遲可能意味著它們會轉到瀏覽其它的網站?假如你的是商業網站,這有可能意味著失去潛在的銷售。
我們沒有任何辦法控制使用者的頻寬,但我們的確能通過最佳化Asp 網站來獲得最佳的效能。大部分潛在效能的提升是通過系統改變而不是緊縮代碼,一個不合適的想法是,一旦遇到系統效率問題,就向系統管理者提意見要其升級系統。
首先,哪個因素可能影響Asp的效能?很不幸,有很多因素?下面這些只是其中的一部分:
可用頻寬
伺服器上的處理器和其它硬體的速度
在伺服器上啟動並執行其它程式(比如象那些OpenGL螢幕保護裝置程式!)
資料庫連接模式,串連池,資料庫系統本身(比如Oracle優於Sql Server,Sql server優於Access)
所使用的語言
預存程序優於行式Sql語句
使用編譯組件而不是VB或JavaScript,好的Asp編程經驗,比如錯誤處理等
一些以上的因素可能已經被有IIS 知識經驗的開發人員普遍留意到了,但其它的可能對於他們來說是十分複雜的問題。在這篇文章裡, 將試著解釋所有影響Asp效能的每個因素,讓我們看一看那些在我們刮鬍子的幾毫秒內就能做到的主要事情。
ASP指令碼大小
你是指令碼頁(還有其它頁面)是不是比必須的長度要長?這是一開始執行就會降低Asp 效能的東西。ASP 指令碼在用來擷取資訊和格式化輸出的時候是十分有用的,但指令碼也是逐行解釋執行,所以你的指令碼越長,執行它的時間也就越長。
如果你的指令碼很龐大,怎麼做才能減少指令碼的長度呢?這裡有幾點建議:
你可以將它們轉換成伺服器端組件,也就是說,做成VB動態連結程式庫DLL或者通過先進的Windows程式設計語言或適當的COM 介面語言將它轉換成未編譯組件?並且在伺服器端註冊它們。有關的快速指南可以在
http://www.webdevelopersjournal.com/articles/activex_for_asp.html找到。對一個寫得好的ActiveX 組件進行編譯不但能大幅度提高效能,還可以保護你的軟體(指令碼),尤其當你將你的Asp網站發布在第三方主機上的時候。
因為指令碼是逐行解釋執行的,所以剔除多餘的指令碼或建立更高效率的指令碼能夠改進效能。如果你在單個Asp 檔案中有數百行的代碼,可能這樣做你能很好地劃分使用者,買賣和資料服務。事實上,如果你這樣做,可能會找出一些冗餘的代碼:如果你需要輸出幾個表格,你可以編寫一個通用函數來輸出一個表格,只是多次調用它。
在講述Asp 指令碼的大小問題的時候,不得不提及包含檔案的大小。當你使用一個包含檔案的時候,整個包含檔案被裝入,當包含檔案被包含的時候,相當於在Asp 檔案本身寫下那部分代碼。因此,如果你在一個冗長的包含檔案裡定義了很多通用的方法和定義,要明白到在你包含該檔案的時候,不管你要不要用到裡面的每個方法和定義,它都是被整個裝入的。ASP 緩衝全部的展開代碼,這會降低尋找效率在這種情況下,包含檔案必須被分割成更小的,模組化的檔案。也要明白到包含檔案被伺服器視為單獨的頁面請求,使用太多的包含檔案會影響下載時間。
〈!-- #include file="Header.asp" --〉
〈!-- #include file="Footer.asp" --〉
〈SCRIPT language="vbscript" runat="server"〉
Sub Main()
WriteHeader
WriteBody
WriteFooter
End Sub
Sub WriteBody()
...
End Sub
Main?'調用過程Main
〈/SCRIPT〉
假如你的指令碼冗長的話,請使用Response.IsClientConnected。這意味著在用戶端不再串連到伺服器的時候,你的伺服器CPU能避免迴圈等待。
〈%
'檢查用戶端是否仍在串連
If Not Response.IsClientConnected Then
'仍然串連著,處理常式
Else
'斷開
End If
%〉
Interspersing ASP and HTML
每個人都這樣做?當我們輸出表格的時候,我們會在ASP 和HTML代碼間轉換,而這是一個不好的習慣。例如:
〈HTML〉
〈BODY〉
〈%
Set MyConn = Server.CreateObject("ADODB.Connection")
MdbFilePath = Server.MapPath("sample.mdb")
MyConn.Open "Driver={Microsoft Access Driver (*.mdb)}; DBQ=" & MdbFilePath & ";"
SQL_query = "SELECT * FROM Friends"
Set RS = MyConn.Execute(SQL_query)
WHILE NOT RS.EOF
%〉
〈LI〉〈%=RS("Name")%〉: 〈A HREF=""〉Homepage〈/A〉
〈%
RS.MoveNext
WEND
%〉
〈/BODY〉
〈/HTML〉
另一個普遍的例子是使用IF語句的時候:
〈%
If Not Session("DBOpen") Then
%〉
〈H1〉Database not connected〈/H1〉
〈%
Else
%〉
〈H1〉Database open〈/H1〉
〈%
End If
%〉
在這些情況下,指令碼效能能通過將伺服器端指令碼寫到一起來,而用Response.write產生Html代碼來提高效能。比如:
〈%
If not Session ("DBOpen") Then
Response.Write "〈H1〉Database not connected〈/H1〉"
Else
Response.Write "〈H1〉Database open〈/H1〉"
End If
%〉
在大的指令碼和很多指令碼的情況下,你將能看到效能的提高。注意這裡盡量避免了使用〈%標記,這樣就能提高效能,ASP不需在執行指令碼的時候計算字元的Ascii碼。
Session狀態
無庸置疑地,在Asp中能夠通過Session維持某個狀態的能力是十分強大的特色。然而,它會影響你的效能。明顯地,你的網站的延展性性變成了另一個問題,如果限制Session的使用的話。然而,session會為每個使用者消耗伺服器資源。
如果你不使用session 變數,或事實上你不必使用?使用隱藏表單域,在資料庫中儲存資料,查詢字串是不是其中的竅門?所以你應該禁止Session狀態。你可以使用下面的聲明禁止使用session:
@EnableSessionState = False
這樣,ASP將不再檢查session資訊。
如果你不得不依賴於session狀態,應該避免在session對象中存放大量的資料。IIS中的session在用戶端的HTTP cookie可用的時候就會保持,導致被session佔用的記憶體在session 終止或逾時前一直被佔用。這樣,如果很多使用者同時使用你的程式的時候,你的伺服器資源可能會耗盡。
資料庫訪問
資料庫訪問是必須的麻煩?訪問資料庫將會激烈地減慢你的程式,但很顯然,如果沒有資料庫,很多網站將變得毫無價值可言。但通過預存程序訪問資料庫來代替使用嵌入式Sql 語句,你可以提升潛在的效能。通過使用預存程序和ActiveX Data Objects (ADO),它們亦同樣擁有良好的靈活性。儘可能從預存程序來輸出資料。
確認你的資料庫具有索引,因為這樣能直接提高你的程式的效率。同樣,盡量在你的資料庫伺服器運行更新統計(Update Statistics) 以協助追蹤你的資料分發,這樣,你的資料庫就能夠基於這些資訊來改造查詢執行。注意一些資料庫比如MS Access,是不是真正能在企業級程式中接受?SQL Sever 7.0或者Oracle是一個更好的賭注。
讓SQL象它被設計的那樣工作,它能count(統計),串連(join),排序(sort)和group 資料。當你能夠寫出一個查詢語句來做這些東西的時候,就不要自己用其它語言來實現。
下面是一個統計所有列的最簡單的文法:
SELECT count(*) FROM publishers WHERE state='NY'
如果你統計一個指定的列,你必須使用group by語句來分組該列,否則它不會工作:
SELECT count(city),city FROM publishers GROUP BY city
分類返回的資料:
SELECT * FROM TableName WHERE FieldName〉50 OR FieldName〈100 ORDER BY FieldName2, Field Name3
使用Odbc還是檔案DSN串連資料庫?使用快速的OLEDB Provider技術串連你的資料庫而不是使用DSN串連。不再需要懇求你的ISP(或資料庫管理員/網管)為你建立一個系統DSN,當你移走Web檔案的時候,亦不需要改變更配置置。
OLEDB 介於ODBC層和應用程式之間。在你的ASP 頁面中,ADO介於ODEDB之上的“應用程式”。你的ADO調用首先被送到OLEDB,接著被送到ODBC層。然而,你可以直接連接到OLEDB 層,並且如果你這樣做的話,你就能看到伺服器端效能的提高。然而,怎樣直接連接到OLEDB?
如果你使用SQLServer 7,使用下面的串連代碼串連資料庫:
strConnString = "DSN='';DRIVER={SQL SERVER};" & _
"UID=myuid;PWD=mypwd;" & _
"DATABASE=MyDb;SERVER=MyServer;"
最重要的參數是DRIVER=部分。如果你要繞過ODBC而使用通過使用OLEDB 串連SQL Server(這是更快的串連),請使用下面的文法:
strConnString ="Provider=SQLOLEDB.1;Password=mypassword;" & _
"Persist Security Info=True;User ID=myuid;" & _
"Initial Catalog=mydbname;" & _
"Data Source=myserver;Connect Timeout=15"
有什麼不對的地方嗎?
現在你可能會覺得有點奇怪:我們在這個新的串連方法中的要點是什麼呢?為什麼不使用標準DSN-less/System DSN途徑?呵,根據Wrox 在他的著作《ADO 2.0 Programmer's Reference》中測試的結果表明,如果你使用OLEDB串連和DSN或者DSN-less串連方法比較,你會發現有下面的改進:
效能對比:
SQL Access
OLEDBDSNOLEDBDSN
連線時間:18?82?連線時間:62?99
查詢1,000條記錄時間:29005400查詢1,000條記錄時間: 100950
注釋:這個結果在Wrox的《ADO 2.0 Programmer's Reference》一書的第232和233頁可以查到。時間的單位是毫秒,查詢1,000記錄時間是通過伺服器端遊標計算出來的(當使用用戶端資料指標的時候,OLEDB與DSN記錄集的效能之間的差別不大)。
ASP解碼問題:
儘可能在用戶端確認使用者輸入來減少HTTP來回請求的數量。如果瀏覽器有支援JavaScript或其它指令碼的能力,使用它們的力量以釋放更多的伺服器資源。
下面的VBScript運行於用戶端瀏覽器,在提交到你的伺服器之前,用來驗證使用者資訊:
〈SCRIPT LANGUAGE="VBScript"〉
〈!--
Sub btnEnter_OnClick
Dim TheForm
Set TheForm = Document.MyForm
If IsNumeric(TheForm.Age.Value) Then
TheForm.submit
Else
Msgbox "Please enter a numerical age."
End if
End Sub
//--〉
〈/SCRIPT〉
〈FORMmethod="POST" name=MyFormaction="myfile.asp"〉? Name: 〈INPUT typr="text" name="Name"〉
Age: 〈INPUT type="text" name="Age"〉
〈INPUT type="button" name="btnEnter"value="Enter"〉
〈/FORM〉
使用局部變數,避免使用全域變數。局部變數比全域變數更快地被Asp 指令碼引擎存取,因為不需搜尋整個名稱域。避免改變數組定義。在第一次初始化的時候就簡單分配足夠的大小效率更高。在這種情況下,你可能會浪費一些記憶體,但你獲得了速度的優勢。在伺服器負載重的時候這個技術是顯然易見有效。
如果你需要引用不一定要用到的對象,那麼最好使用〈OBJECT〉標記而不是用 Server.CreateObject方法。 使用Server.CreateObject引起對象立即被建立,反之,〈OBJECT〉標記則不會這樣立即建立對象如果使用〈object〉定義後不使用該對象,你不會浪費資源。
例如:下面的例子是一個使用〈OBJECT〉標記建立一個application-scope廣告輪 Ad Rotator對象實
例:
〈OBJECT runat=server scope=Application id=MyAds progid="MSWC.AdRotator"〉
〈/OBJECT〉
在儲存該Ad Rotator對象進Application後,你可以在任何程式的頁面中用下面的文法訪問該對象
〈%=MyAds.GetAdvertisement("CustomerAds.txt") %〉
開啟'Option Explicit'開關。在VB和VBScript 中,你可以在沒有顯式聲明的情況下使用變數。但開啟這個選項可以鑒別用定義變數,這樣可以很好地書寫變數,並能協助提高效能。未定義的局部變數會變慢,因為在建立它之前,名稱空間必須被搜遍後才知道變數是否存在。擺脫它,使每個變數清楚地定義(先定義後使用)。
這是一個好習慣,it may trap typos, 這樣更快。
除非你真正需要使用,否而不要使用Server.MapPath方法。如果你知道真實路徑就使用真實路徑。使用MapPath需要IIS找回現時伺服器路徑,這意味著得向伺服器發一個特殊的請求,也就意味著降低了效能。另一個方法是將路徑存放到局部變數中,在需要的時候使用,這樣就不需要伺服器多次尋找。
檢查你自己是怎麼做的
你可以通過工具來測量你的系統效能,比如系統效能監控器,NetMon和PerfMon。測試web效能可以用WCAT (Web Capacity Analysis Tool)。使用WCAT,你可以測試你的IIS伺服器和網路設定響應各種各樣的客戶請求,資料或HTML頁面的能力。這些測試結果能夠被用來作為最佳化你的伺服器和網路設定的指導。WCAT是專門設計用來估計Windows 2000中的網際網路服務(或Windows NT)和IIS 能響應的客戶工作量
(模擬)。為了得到更多的資訊,請參閱IIS Resource Kit(資源工具包)。那裡也有冗長的WCAT使用者指南在MSDN線上Web sorkshop網站裡面有一個下載連結。如果你認真對待你的Asp 效能的話,務必取得該工具。
力求最佳化應用程式效能,你的web 應用程式會運行更加順暢。如果不是真正需要,就不要影響伺服器的效能。
總結:上面介紹了有關ASP效能的資料,有很多因素影響Asp的效能,這裡只討論了其中的一部分。作為最終的想法,不要認為你能夠處理好所有的因素,你的ASP 效能還是有必要提高的。你發布的每個應用程式必須個別進行考慮,所有以上的技巧並不是適合每個Asp程式。