Len Cardinal - Microsoft Consulting Services 高級顧問 George V. Reilly - Microsoft IIS Performance 主管 更新時間:2000年4月 根據 Nancy Cluts 的文章(英文)改寫 Nancy Cluts - 開發人員技術工程師 Microsoft Corporation
性能是一個特性。您需要預先設計性能,或是在日后重新編寫應用程序。換句話說,什么是最大限度優化 Active Server Pages (ASP) 應用程序性能的好策略?
本文為優化 ASP 應用程序和“Visual Basic(R) 腳本編輯器 (VBScript)”提供了許多技巧。對許多陷阱和缺陷進行了討論。本文所列的建議均在 http://www.microsoft.com 及其他站點上進行了測試,而且工作正常。本文假定您對 ASP 開發有基本的理解,包括對 VBScript 和/或 JScript、ASP Application、ASP Session 和其他 ASP 內部對象(請求、響應和服務器)。
ASP 的性能,通常不止取決于 ASP 代碼本身。我們并不想在一篇文章中囊括所有的至理名言,只在最后列出與性能相關的資源。這些鏈接包括 ASP 和非 ASP 主題,包括“ActiveX(R) 數據對象 (ADO)”、“部件對象模型 (COM)”、數據庫和“Internet 信息服務器 (IIS)”配置。這些是我們喜歡的鏈接 - 務請關注它們。
技巧 1:在 Web 服務器上緩存常用數據
典型的 ASP 頁從后端數據庫檢索數據,然后將結果轉換為超文本標記語言 (HTML)。無論數據庫的速度如何,從內存檢索數據要比從后端數據庫檢索數據快得多。從本地硬盤讀取數據通常也要比從數據庫檢索數據快得多。因此,通常可以通過在 Web 服務器(在內存或磁盤)上緩存數據來改善性能。
<% Function GetEmploymentStatusList Dim d d = Application("EmploymentStatusList") If d = "" Then ' FetchEmploymentStatusList 函數(不顯示) ' 從 DB 中取出數據,返回數組 d = FetchEmploymentStatusList() Application("EmploymentStatusList") = d End If GetEmploymentStatusList = d End Function %>
' 取記錄集,以數組返回 Function FetchEmploymentStatusList Dim rs Set rs = CreateObject("ADODB.Recordset") rs.Open "select StatusName, StatusID from EmployeeStatus", _ "dsn=employees;uid=sa;pwd=;" FetchEmploymentStatusList = rs.GetRows() ' 以數組返回數據 rs.Close Set rs = Nothing End Function
對上面示例的進一步改進應當是緩存該列表的 HTML,而不是緩存數組。下面是一個簡單的范例:
' 取記錄集,以“HTML 選項”列表返回 Function FetchEmploymentStatusList Dim rs, fldName, s Set rs = CreateObject("ADODB.Recordset") rs.Open "select StatusName, StatusID from EmployeeStatus", _ "dsn=employees;uid=sa;pwd=;" s = "<select name=""EmploymentStatus">" & vbCrLf Set fldName = rs.Fields("StatusName") ' ADO 字段綁定 Do Until rs.EOF ' 下面一行違背了不要進行字符串連接, ' 但這是可以的,因為我們正在建立高速緩存 s = s & " <option>" & fldName & "</option>" & vbCrLf rs.MoveNext Loop s = s & "</select>" & vbCrLf rs.Close Set rs = Nothing ' 參見盡早釋放 FetchEmploymentStatusList = s ' 以字符串返回數據 End Function
如果在 Application 或 Session 作用域中存儲數據,這些數據將一直保留在那兒,直到在程序中改變它、Session 過期或 Web 應用程序重新啟動時為止。數據需要更新如何處理?若要用手工強制更新應用程序數據,可以調用只允許管理員訪問的數據更新 ASP 頁。另外,還可以通過函數,周期地自動刷新數據。下面的示例存儲帶緩存數據的時間戳,在指定時間間隔后刷新數據。
' 函數返回雇傭狀態列表 Function GetEmploymentStatusList UpdateEmploymentStatus GetEmploymentStatusList = Application("EmploymentStatusList") End Function
' 定期更新緩存的數據 Sub UpdateEmploymentStatusList Dim d, strLastUpdate strLastUpdate = Application("LastUpdate") If (strLastUpdate = "") Or _ (UPDATE_INTERVAL DateDiff("s", strLastUpdate, Now)) Then
' FetchEmploymentStatusList 函數(不顯示) ' 從 DB 中取數據,返回一個數組 d = FetchEmploymentStatusList()
' 更新 Application 對象。用 Application.Lock() ' 來確保一致的數據 Application.Lock Application("EmploymentStatusList") = d Application("LastUpdate") = CStr(Now) Application.Unlock End If End Sub
有時,數據過多不能在內存中進行緩存?!斑^多”是一種定性的判斷;它取決于打算消耗的內存量,還有緩存項的數量和這些項的檢索頻率。總之,如果有過多的數據要在內存中緩存,請考慮以文本或 XML 文件的形式,在 Web 服務器的硬盤上緩存數據??梢詫⒃诖疟P上緩存數據和在內存中緩存數據組合起來,為站點建立最優的緩存策略。
注意,在度量單個 ASP 頁的性能時,在磁盤上檢索數據不一定比從數據庫中檢索數據快。但是,緩存減輕了數據庫和網絡的負荷。在高負荷情況下,這將明顯提高總體通信量。在查詢成本很高時緩存查詢的結果,緩存便非常有效,例如多表聯合或復雜的存儲過程,或緩存大型的結果集。按照慣例,測試競爭方案。
ASP 和 COM 提供了幾種構建磁盤緩存方案的工具。ADO 記錄集的 Save() 和 Open() 函數,保存和加載磁盤上的記錄集。您可以使用這些方法重寫上面 Application 數據緩存技巧中的范例代碼,用 Save() 文件替換向 Application 對象寫入數據的代碼。
還有其他一些處理文件的組件:
Scripting.FileSystemObject 使您能夠創建、讀取和寫入文件。 MSXML 是隨 Internet Explorer 提供的 Microsoft(R) XML 解析器,它支持保存和加載 XML 文檔。 LookupTable 對象(在 MSN 上使用的范例)是從磁盤加載簡單列表的良好選擇。 最后,請考慮在磁盤上緩存數據的表示,而不是數據本身。預制的 HTML 可以作為 .htm 或 .asp 文件存儲在磁盤上;超級鏈接可以直接指向這些文件??梢允褂蒙虡I工具,如 XBuilder 或 Microsoft(R) SQL Server 的 Internet 發行功能來自動化 HTML 生成過程。另外,可以將 HTML 片段 #include 到 .asp 文件。還可以使用 FileSystemObject 從磁盤讀取 HTML 文件或使用 XML 進行早期調整(英文)。
技巧 4:避免在 Application 或 Session 對象中緩存非靈活組件
雖然在 Application 或 Session 對象中緩存數據是個好主意,但是緩存 COM 對象可能有嚴重缺陷。將常用 COM 對象嵌入 Application 或 Session 對象通常具有吸引力。遺憾的是,很多 COM 對象,包括用 Visual Basic 6.0 或更早版本編寫的 COM 對象,在 Application 或 Session 對象中存儲時將導致嚴重的瓶頸。