微軟建議的ASP優(yōu)化性能28條守則(1)
發(fā)表時(shí)間:2024-02-07 來(lái)源:明輝站整理相關(guān)軟件相關(guān)文章人氣:
[摘要]引言 性能是一個(gè)特征。您必須預(yù)先設(shè)計(jì)性能,否則您以后就得重寫(xiě)應(yīng)用程序。就是說(shuō),有哪些好的策略可使 Active Server Pages (ASP) 應(yīng)用程序性能達(dá)到最佳? 本文介紹了優(yōu)化 ASP 應(yīng)用程序和 Visual Basic® Scripting Edition (VBS...
引言
性能是一個(gè)特征。您必須預(yù)先設(shè)計(jì)性能,否則您以后就得重寫(xiě)應(yīng)用程序。就是說(shuō),有哪些好的策略可使 Active Server Pages (ASP) 應(yīng)用程序性能達(dá)到最佳?
本文介紹了優(yōu)化 ASP 應(yīng)用程序和 Visual Basic® Scripting Edition (VBScript) 的技巧。本文討論了許多陷阱。本文列出的建議已經(jīng)在 http://www.microsoft.com 和其它站點(diǎn)中進(jìn)行了測(cè)試,效果十分顯著。本文假定您已經(jīng)對(duì) ASP 開(kāi)發(fā),包括 VBScript 和/或 JScript、ASP Application、ASP Session 和其它 ASP 固有對(duì)象(Request、Response 和 Server)有了基本了解。
通常,ASP 性能主要取決于 ASP 代碼本身以外的很多因素。我們不在一篇文章中羅列出所有的信息,在本文結(jié)尾處我們列出了與性能有關(guān)的資源。這些鏈接涵蓋了 ASP 和非 ASP 主題,包括 ActiveX® 數(shù)據(jù)對(duì)象 (ADO)、組件對(duì)象模型 (COM)、數(shù)據(jù)庫(kù)和 Internet Information Server (IIS) 配置。這些都是我們喜歡的一些鏈接 - 一定要去看看。
技巧 1:將經(jīng)常使用的數(shù)據(jù)緩存在 Web 服務(wù)器上
典型的 ASP 頁(yè)從后端數(shù)據(jù)存儲(chǔ)中檢索數(shù)據(jù),然后將結(jié)果轉(zhuǎn)換成超文本標(biāo)記語(yǔ)言 (HTML)。無(wú)論數(shù)據(jù)庫(kù)的速度如何,從內(nèi)存中檢索數(shù)據(jù)總要比從后端數(shù)據(jù)存儲(chǔ)中檢索數(shù)據(jù)快得多。從本地硬盤(pán)讀取數(shù)據(jù)通常也比從數(shù)據(jù)庫(kù)中檢索數(shù)據(jù)更快。因此,通?梢詫(shù)據(jù)緩存在 Web 服務(wù)器上(存儲(chǔ)在內(nèi)存或磁盤(pán)中),來(lái)提高性能。
緩存是傳統(tǒng)的以空間換取時(shí)間的做法。如果您緩存的內(nèi)容正確,那么您可以看到性能會(huì)有顯著的提高。為使緩存有效,必須保存那些經(jīng)常重復(fù)使用的數(shù)據(jù),且要重新計(jì)算這些數(shù)據(jù)需要(適度)大的開(kāi)銷(xiāo)。如果緩存的都是些陳舊的數(shù)據(jù),就會(huì)造成內(nèi)存浪費(fèi)。
不經(jīng)常發(fā)生改變的數(shù)據(jù)是很好的緩存候選數(shù)據(jù),因?yàn)槟槐負(fù)?dān)心隨著時(shí)間的遷移該數(shù)據(jù)與數(shù)據(jù)庫(kù)同步的問(wèn)題。組合框列表、引用表、DHTML 碎片、擴(kuò)展標(biāo)記語(yǔ)言 (XML) 字符串、菜單項(xiàng)和站點(diǎn)配置變量(包括數(shù)據(jù)源名稱(chēng) (DSN)、Internet 協(xié)議 (IP) 地址和 Web 路徑)都是很好的緩存候選內(nèi)容。注意您可以緩存數(shù)據(jù)的“表示”,而不緩存數(shù)據(jù)本身。如果 ASP 頁(yè)很少更改,且緩存的開(kāi)銷(xiāo)也很大(例如,整個(gè)產(chǎn)品目錄),則應(yīng)考慮事先產(chǎn)生 HTML,而不是在響應(yīng)每個(gè)請(qǐng)求時(shí)重新顯示。
應(yīng)將數(shù)據(jù)緩存在哪里,有哪些緩存策略?通常,數(shù)據(jù)緩存在 Web 服務(wù)器的內(nèi)存或磁盤(pán)中。下兩個(gè)技巧講述了這兩個(gè)方法。
技巧 2: 將經(jīng)常使用的數(shù)據(jù)緩存在 Application 或 Session 對(duì)象中
ASP Application 和 Session 對(duì)象為將數(shù)據(jù)緩存在內(nèi)存中提供了方便的容器。您可以將數(shù)據(jù)指派到 Application 和 Session 對(duì)象中,這些數(shù)據(jù)在 HTTP 調(diào)用之間保留在內(nèi)存中。Session 數(shù)據(jù)是按每個(gè)用戶(hù)分別存儲(chǔ)的,而 Application 數(shù)據(jù)則在所有用戶(hù)之間共享。
什么時(shí)候?qū)?shù)據(jù)裝載到 Application 或 Session 中呢?通常,數(shù)據(jù)是在啟動(dòng) Application 或 Session 時(shí)裝載。要在 Application 或 Session 啟動(dòng)過(guò)程中裝載數(shù)據(jù),應(yīng)將適當(dāng)?shù)拇a分別添加到 Application_OnStart() 或 Session_OnStart() 中。這些函數(shù)應(yīng)在 Global.asa 中,如果沒(méi)有,則可以添加這些函數(shù)。還可以在第一次需要時(shí)裝載該數(shù)據(jù)。為此,在 ASP 頁(yè)中添加一些代碼(或編寫(xiě)一個(gè)可重復(fù)使用的腳本函數(shù)),以檢查數(shù)據(jù)是否存在,如果不存在,就裝載數(shù)據(jù)。這是一個(gè)傳統(tǒng)的性能技術(shù),稱(chēng)為“惰性計(jì)算” - 在您知道需要某一個(gè)值以前不計(jì)算該值。例如:
<%
Function GetEmploymentStatusList
Dim d
d = Application(?EmploymentStatusList?)
If d = ?? Then
' FetchEmploymentStatusList function (not shown)
' fetches data from DB, returns an Array
d = FetchEmploymentStatusList()
Application(?EmploymentStatusList?) = d
End If
GetEmploymentStatusList = d
End Function
%>
可以為所需要的每個(gè)數(shù)據(jù)塊編寫(xiě)類(lèi)似的函數(shù)。
應(yīng)以什么格式存儲(chǔ)數(shù)據(jù)?可以存儲(chǔ)任何變體類(lèi)型,因?yàn)樗心_本變量都是變體型。例如,您可以存儲(chǔ)字符串、整數(shù)或數(shù)組。通常,您將以這些變量類(lèi)型之一存儲(chǔ) ADO 記錄集的內(nèi)容。要從 ADO 記錄集獲取數(shù)據(jù),您可以手工將數(shù)據(jù)復(fù)制到 VBScript 變量,一次一個(gè)字段。使用一個(gè) ADO 記錄集持久函數(shù) GetRows()、GetString() 或 Save()(ADO 2.5),可加快速度且更容易一些。其詳細(xì)情況已超出本文所討論的范圍,但下面給出了一個(gè)函數(shù)舉例,說(shuō)明使用 GetRows() 返回記錄集數(shù)據(jù)的一個(gè)數(shù)組:
' Get Recordset, return as an Array
Function FetchEmploymentStatusList
Dim rs
Set rs = CreateObject(?ADODB.Recordset?)
rs.Open ?select StatusName, StatusID from EmployeeStatus?, _
?dsn=employees;uid=sa;pwd=;?
FetchEmploymentStatusList = rs.GetRows() ? Return data as an Array
rs.Close
Set rs = Nothing
End Function
對(duì)上面舉例做更進(jìn)一步改進(jìn),可以將 HTML 緩存為列表,而不是數(shù)組。下面是簡(jiǎn)單的示例:
' Get Recordset, return as HTML Option list
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 Field Binding
Do Until rs.EOF
' Next line violates Don't Do String Concats,
' but it's OK because we are building a cache
s = s & ? <option>? & fldName & ?</option>? & vbCrLf
rs.MoveNext
Loop
s = s & ?</select>? & vbCrLf
rs.Close
Set rs = Nothing ' See Release Early
FetchEmploymentStatusList = s ' Return data as a String
End Function
在適當(dāng)?shù)臈l件下,可以將 ADO 記錄集本身緩存在 Application 或 Session 作用域中。有兩個(gè)警告:
必須將 ADO 標(biāo)記為自由線(xiàn)程
必須使用斷開(kāi)連接的記錄集。
如果不能保證滿(mǎn)足這兩個(gè)要求,則不要緩存 ADO 記錄集。在下面的“非敏捷組件”和“不要緩存連接”技巧中,我們將討論將 COM 對(duì)象存儲(chǔ)在 Application 或 Session 作用域中的危險(xiǎn)性。
當(dāng)您將數(shù)據(jù)存儲(chǔ)在 Application 或 Session 作用域時(shí),數(shù)據(jù)將保留在那里,直到您以編程方式改變它、Session 過(guò)期或 Web 應(yīng)用程序重新啟動(dòng)為止。如果數(shù)據(jù)需要更新怎么辦?要手工強(qiáng)制對(duì) Application 數(shù)據(jù)進(jìn)行更新,您可以訪(fǎng)問(wèn)只有管理員才可訪(fǎng)問(wèn)的 ASP 頁(yè)來(lái)更新數(shù)據(jù);蛘,您可以通過(guò)函數(shù)定期自動(dòng)刷新數(shù)據(jù)。下面例子存儲(chǔ)帶有緩存數(shù)據(jù)的時(shí)間戳,并隔一段時(shí)間后刷新數(shù)據(jù)。
<%
' error handing not shown...
Const UPDATE_INTERVAL = 300 ' Refresh interval, in seconds
' Function to return the employment status list
Function GetEmploymentStatusList
UpdateEmploymentStatus
GetEmploymentStatusList = Application(?EmploymentStatusList?)
End Function
' Periodically update the cached data
Sub UpdateEmploymentStatusList
Dim d, strLastUpdate
strLastUpdate = Application(?LastUpdate?)
If (strLastUpdate = ??) Or _
(UPDATE_INTERVAL < DateDiff(?s?, strLastUpdate, Now)) Then
' Note: two or more calls might get in here. This is okay and will simply
' result in a few unnecessary fetches (there is a workaround for this)
' FetchEmploymentStatusList function (not shown)
' fetches data from DB, returns an Array
d = FetchEmploymentStatusList()
' Update the Application object. Use Application.Lock()
' to ensure consistent data
Application.Lock
Application(?EmploymentStatusList?) = Events
Application(?LastUpdate?) = CStr(Now)
Application.Unlock
End If
End Sub
請(qǐng)參見(jiàn) World's Fastest ListBox with Application Data,上面還有一個(gè)例子。
要知道在 Session 或 Application 對(duì)象中緩存大的數(shù)組不是一個(gè)好的做法。在訪(fǎng)問(wèn)數(shù)組的任何元素之前,腳本語(yǔ)言的語(yǔ)法要求必須臨時(shí)復(fù)制整個(gè)數(shù)組。例如,如果將由字符串組成的有 100,000 個(gè)元素的數(shù)組(該數(shù)組將美國(guó)郵政編碼映射到當(dāng)?shù)氐臍庀笳荆┚彺嬖?Application 對(duì)象中,ASP 必須先將所有的 100,000 個(gè)氣象站復(fù)制到臨時(shí)數(shù)組中,然后才能提取一個(gè)字符串。在這種情況下,用自定義方法建立一個(gè)自定義組件來(lái)存儲(chǔ)氣象站 - 或使用一個(gè)詞典組件會(huì)更好。
再警告大家一下,不要將嬰兒與洗澡水一起倒掉:數(shù)組能快速查尋和存儲(chǔ)在內(nèi)存中是鄰近的關(guān)鍵數(shù)據(jù)對(duì)。索引一個(gè)詞典比索引一個(gè)數(shù)組要慢得多。應(yīng)針對(duì)您的實(shí)際情況,選擇提供最佳性能的數(shù)據(jù)結(jié)構(gòu)。