引言
性能是一个特征您必须预先设计性能否则您以后就得重写应用程序就是说有哪些好的策略可使 Active Server Pages (ASP) 应用程序性能达到最佳?
本文介绍了优化 ASP 应用程序和 Visual Basic® Scripting Edition (VBScript) 的技巧本文讨论了许多陷阱本文列出的建议已经在 和其它站点中进行了测试效果十分显着本文假定您已经对 ASP 开发包括 VBScript 和/或 JScriptASP ApplicationASP Session 和其它 ASP 固有对象(RequestResponse 和 Server)有了基本了解
通常ASP 性能主要取决于 ASP 代码本身以外的很多因素我们不在一篇文章中罗列出所有的信息在本文结尾处我们列出了与性能有关的资源这些链接涵盖了 ASP 和非 ASP 主题包括 ActiveX® 数据对象 (ADO)组件对象模型 (COM)数据库和 Internet Information Server (IIS) 配置这些都是我们喜欢的一些链接 一定要去看看
技巧 将经常使用的数据缓存在 Web 服务器上
典型的 ASP 页从后端数据存储中检索数据然后将结果转换成超文本标记语言 (HTML)无论数据库的速度如何从内存中检索数据总要比从后端数据存储中检索数据快得多从本地硬盘读取数据通常也比从数据库中检索数据更快因此通常可以将数据缓存在 Web 服务器上(存储在内存或磁盘中)来提高性能
缓存是传统的以空间换取时间的做法如果您缓存的内容正确那么您可以看到性能会有显着的提高为使缓存有效必须保存那些经常重复使用的数据且要重新计算这些数据需要(适度)大的开销如果缓存的都是些陈旧的数据就会造成内存浪费
不经常发生改变的数据是很好的缓存候选数据因为您不必担心随着时间的迁移该数据与数据库同步的问题组合框列表引用表DHTML 碎片扩展标记语言 (XML) 字符串菜单项和站点配置变量(包括数据源名称 (DSN)Internet 协议 (IP) 地址和 Web 路径)都是很好的缓存候选内容注意您可以缓存数据的表示而不缓存数据本身如果 ASP 页很少更改且缓存的开销也很大(例如整个产品目录)则应考虑事先产生 HTML而不是在响应每个请求时重新显示
应将数据缓存在哪里有哪些缓存策略?通常数据缓存在 Web 服务器的内存或磁盘中下两个技巧讲述了这两个方法
技巧 : 将经常使用的数据缓存在 Application 或 Session 对象中
ASP Application 和 Session 对象为将数据缓存在内存中提供了方便的容器您可以将数据指派到 Application 和 Session 对象中这些数据在 HTTP 调用之间保留在内存中Session 数据是按每个用户分别存储的而 Application 数据则在所有用户之间共享
什么时候将数据装载到 Application 或 Session 中呢?通常数据是在启动 Application 或 Session 时装载要在 Application 或 Session 启动过程中装载数据应将适当的代码分别添加到 Application_OnStart() 或 Session_OnStart() 中这些函数应在 Globalasa 中如果没有则可以添加这些函数还可以在第一次需要时装载该数据为此在 ASP 页中添加一些代码(或编写一个可重复使用的脚本函数)以检查数据是否存在如果不存在就装载数据这是一个传统的性能技术称为惰性计算 在您知道需要某一个值以前不计算该值例如
<%
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
%>
可以为所需要的每个数据块编写类似的函数
应以什么格式存储数据?可以存储任何变体类型因为所有脚本变量都是变体型例如您可以存储字符串整数或数组通常您将以这些变量类型之一存储 ADO 记录集的内容要从 ADO 记录集获取数据您可以手工将数据复制到 VBScript 变量一次一个字段使用一个 ADO 记录集持久函数 GetRows()GetString() 或 Save()(ADO )可加快速度且更容易一些其详细情况已超出本文所讨论的范围但下面给出了一个函数举例说明使用 GetRows() 返回记录集数据的一个数组
Get Recordset return as an Array
Function FetchEmploymentStatusList
Dim rs
Set rs = CreateObject(?ADODBRecordset?)
rsOpen ?select StatusName StatusID from EmployeeStatus? _
?dsn=employees;uid=sa;pwd=;?
FetchEmploymentStatusList = rsGetRows() ? Return data as an Array
rsClose
Set rs = Nothing
End Function
对上面举例做更进一步改进可以将 HTML 缓存为列表而不是数组下面是简单的示例
Get Recordset return as HTML Option list
Function FetchEmploymentStatusList
Dim rs fldName s
Set rs = CreateObject(?ADODBRecordset?)
rsOpen ?select StatusName StatusID from EmployeeStatus? _
?dsn=employees;uid=sa;pwd=;?
s = ?<select name=??EmploymentStatus??>? & vbCrLf
Set fldName = rsFields(?StatusName?) ADO Field Binding
Do Until rsEOF
Next line violates Dont Do String Concats
but its OK because we are building a cache
s = s & ? <option>? & fldName & ?</option>? & vbCrLf
rsMoveNext
Loop
s = s & ?</select>? & vbCrLf
rsClose
Set rs = Nothing See Release Early
FetchEmploymentStatusList = s Return data as a String
End Function
在适当的条件下可以将 ADO 记录集本身缓存在 Application 或 Session 作用域中有两个警告
必须将 ADO 标记为自由线程
必须使用断开连接的记录集
如果不能保证满足这两个要求则不要缓存 ADO 记录集在下面的非敏捷组件和不要缓存连接技巧中我们将讨论将 COM 对象存储在 Application 或 Session 作用域中的危险性
当您将数据存储在 Application 或 Session 作用域时数据将保留在那里直到您以编程方式改变它Session 过期或 Web 应用程序重新启动为止如果数据需要更新怎么办?要手工强制对 Application 数据进行更新您可以访问只有管理员才可访问的 ASP 页来更新数据或者您可以通过函数定期自动刷新数据下面例子存储带有缓存数据的时间戳并隔一段时间后刷新数据
<%
error handing not shown
Const UPDATE_INTERVAL = 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 ApplicationLock()
to ensure consistent data
ApplicationLock
Application(?EmploymentStatusList?) = Events
Application(?LastUpdate?) = CStr(Now)
ApplicationUnlock
End If
End Sub
请参见 Worlds Fastest ListBox with Application Data上面还有一个例子
要知道在 Session 或 Application 对象中缓存大的数组不是一个好的做法在访问数组的任何元素之前脚本语言的语法要求必须临时复制整个数组例如如果将由字符串组成的有 个元素的数组(该数组将美国邮政编码映射到当地的气象站)缓存在 Application 对象中ASP 必须先将所有的 个气象站复制到临时数组中然后才能提取一个字符串在这种情况下用自定义方法建立一个自定义组件来存储气象站 或使用一个词典组件会更好
再警告大家一下不要将婴儿与洗澡水一起倒掉数组能快速查寻和存储在内存中是邻近的关键数据对索引一个词典比索引一个数组要慢得多应针对您的实际情况选择提供最佳性能的数据结构
技巧 将数据和 HTML 缓存在 Web 服务器的磁盘上
有时数据可能太多无法都缓存在内存中太多只是一个说法这要看您想消耗多少内存以及需缓存的项目数和检索这些项目的频率在任何情况下如果数据太多而无法都缓存在内存中则考虑