技巧|性能
引言
性能是一个特征。您必须预先设计性能,否则您以后就得重写应用程序。就是说,有哪些好的策略可使ActiveServerPages(ASP)应用程序性能达到最佳?
本文介绍了优化ASP应用程序和VisualBasic®ScriptingEdition(VBScript)的技巧。本文讨论了许多陷阱。本文列出的建议已经在和其它站点中进行了测试,效果十分显著。本文假定您已经对ASP开发,包括VBScript和/或JScript、ASPApplication、ASPSession和其它ASP固有对象(Request、Response和Server)有了基本了解。
通常,ASP性能主要取决于ASP代码本身以外的很多因素。我们不在一篇文章中罗列出所有的信息,在本文结尾处我们列出了与性能有关的资源。这些链接涵盖了ASP和非ASP主题,包括ActiveX®数据对象(ADO)、组件对象模型(COM)、数据库和InternetInformationServer(IIS)配置。这些都是我们喜欢的一些链接-一定要去看看。
技巧1:将经常使用的数据缓存在Web服务器上
典型的ASP页从后端数据存储中检索数据,然后将结果转换成超文本标记语言(HTML)。无论数据库的速度如何,从内存中检索数据总要比从后端数据存储中检索数据快得多。从本地硬盘读取数据通常也比从数据库中检索数据更快。因此,通常可以将数据缓存在Web服务器上(存储在内存或磁盘中),来提高性能。
缓存是传统的以空间换取时间的做法。如果您缓存的内容正确,那么您可以看到性能会有显著的提高。为使缓存有效,必须保存那些经常重复使用的数据,且要重新计算这些数据需要(适度)大的开销。如果缓存的都是些陈旧的数据,就会造成内存浪费。
不经常发生改变的数据是很好的缓存候选数据,因为您不必担心随着时间的迁移该数据与数据库同步的问题。组合框列表、引用表、DHTML碎片、扩展标记语言(XML)字符串、菜单项和站点配置变量(包括数据源名称(DSN)、Internet协议(IP)地址和Web路径)都是很好的缓存候选内容。注意您可以缓存数据的“表示”,而不缓存数据本身。如果ASP页很少更改,且缓存的开销也很大(例如,整个产品目录),则应考虑事先产生HTML,而不是在响应每个请求时重新显示。
应将数据缓存在哪里,有哪些缓存策略?通常,数据缓存在Web服务器的内存或磁盘中。下两个技巧讲述了这两个方法。
技巧2:将经常使用的数据缓存在Application或Session对象中
ASPApplication和Session对象为将数据缓存在内存中提供了方便的容器。您可以将数据指派到Application和Session对象中,这些数据在HTTP调用之间保留在内存中。Session数据是按每个用户分别存储的,而Application数据则在所有用户之间共享。
什么时候将数据装载到Application或Session中呢?通常,数据是在启动Application或Session时装载。要在Application或Session启动过程中装载数据,应将适当的代码分别添加到或中。这些函数应在Global.asa中,如果没有,则可以添加这些函数。还可以在第一次需要时装载该数据。为此,在ASP页中添加一些代码(或编写一个可重复使用的脚本函数),以检查数据是否存在,如果不存在,就装载数据。这是一个传统的性能技术,称为“惰性计算”-在您知道需要某一个值以前不计算该值。例如:
<%
FunctionGetEmploymentStatusList
Dimd
d=Application(?EmploymentStatusList?)
Ifd=??Then
'FetchEmploymentStatusListfunction(notshown)
'fetchesdatafromDB,returnsanArray
d=FetchEmploymentStatusList()
Application(?EmploymentStatusList?)=d
EndIf
GetEmploymentStatusList=d
EndFunction
%>
可以为所需要的每个数据块编写类似的函数。
应以什么格式存储数据?可以存储任何变体类型,因为所有脚本变量都是变体型。例如,您可以存储字符串、整数或数组。通常,您将以这些变量类型之一存储ADO记录集的内容。要从ADO记录集获取数据,您可以手工将数据复制到VBScript变量,一次一个字段。使用一个ADO记录集持久函数GetRows()、GetString()或Save()(ADO2.5),可加快速度且更容易一些。其详细情况已超出本文所讨论的范围,但下面给出了一个函数举例,说明使用返回记录集数据的一个数组:
'GetRecordset,returnasanArray
FunctionFetchEmploymentStatusList
Dimrs
Setrs=CreateObject(?ADODB.Recordset?)
rs.Open?selectStatusName,StatusIDfromEmployeeStatus?,_
?dsn=employees;uid=sa;pwd=;?
FetchEmploymentStatusList=rs.GetRows()?ReturndataasanArray
rs.Close
Setrs=Nothing
EndFunction
对上面举例做更进一步改进,可以将HTML缓存为列表,而不是数组。下面是简单的示例:
'GetRecordset,returnasHTMLOptionlist
FunctionFetchEmploymentStatusList
Dimrs,fldName,s
Setrs=CreateObject(?ADODB.Recordset?)
rs.Open?selectStatusName,StatusIDfromEmployeeStatus?,_
?dsn=employees;uid=sa;pwd=;?
s=?<selectname=??EmploymentStatus??>?&vbCrLf
SetfldName=rs.Fields(?StatusName?)'ADOFieldBinding
DoUntilrs.EOF
'NextlineviolatesDon'tDoStringConcats,
'butit'sOKbecausewearebuildingacache
s=s&?<option>?&fldName&?</option>?&vbCrLf
rs.MoveNext
Loop
s=s&?</select>?&vbCrLf
rs.Close
Setrs=Nothing'SeeReleaseEarly
FetchEmploymentStatusList=s'ReturndataasaString
EndFunction
在适当的条件下,可以将ADO记录集本身缓存在Application或Session作用域中。有两个警告:
如果不能保证满足这两个要求,则不要缓存ADO记录集。在下面的“非敏捷组件”和“不要缓存连接”技巧中,我们将讨论将COM对象存储在Application或Session作用域中的危险性。
当您将数据存储在Application或Session作用域时,数据将保留在那里,直到您以编程方式改变它、Session过期或Web应用程序重新启动为止。如果数据需要更新怎么办?要手工强制对Application数据进行更新,您可以访问只有管理员才可访问的ASP页来更新数据。或者,您可以通过函数定期自动刷新数据。下面例子存储带有缓存数据的时间戳,并隔一段时间后刷新数据。