纲要:ASP动态生成的内容以什么方式输出效率最高?最好用哪种方法提取数据库记录集?本文测试了近20个这类ASP开发中常见的问题,测试工具所显示的时间告诉我们:这些通常可以想当然的问题不仅值得关注,而且还有出乎意料的秘密隐藏在内。
一、测试目的
本文的第一部分考察了ASP开发中的一些基本问题,给出了一些性能测试结果以帮助读者理解放入页面的代码到底对性能有什么影响。ADO是由Microsoft开发的一个通用、易用的数据库接口,事实证明通过ADO与数据库交互是ASP最重要的应用之一,在第二部分中,我们就来研究这个问题。
ADO所提供的功能相当广泛,因此准备本文最大的困难在于如何界定问题的范围。考虑到提取大量的数据可能显著地增加Web服务器的负载,所以我们决定这一部分的主要目的是找出什么才是操作ADO记录集的最优配置。然而,即使缩小了问题的范围,我们仍旧面临很大的困难,因为ADO可以有许多种不同的方法来完成同一个任务。例如,记录集不仅可以通过Recordset类提取,而且也可以通过Connection和Command类提取;即使得到记录集对象之后,还有许多可能戏剧性地影响性能的操作方法。然而,与第一部分一样,我们将尽可能地涵盖最广泛的问题。
具体地讲,这一部分的目标是收集足够多的信息,回答下列问题:
l是否应该通过包含引用ADOVBS.inc?
l使用记录集时是否应该创建单独的连接对象?
l最好用哪种方法提取记录集?
l哪种游标类型和记录锁定方式效率最高?
l是否应该使用本地记录集?
l设置记录集属性用哪种方法最好?
l用哪种方法引用记录集字段值效率最高?
l用临时字符串收集输出是一种好方法吗?
二、测试环境
本测试总共用到了21个ASP文件,这些文件可以从本文后面下载。每一个页面设置成可以运行三种不同的查询,分别返回0、25、250个记录。这将帮助我们隔离页面本身的初始化、运行开销与用循环访问记录集的开销。
为便于测试,数据库连接字符串和SQL命令串都在Global.asa中作为Application变量保存。由于我们的测试数据库是SQL Server 7.0,因此连接串指定OLEDB作为连接提供者,测试数据来自SQL Server的Northwind数据库。SQL SELECT命令从NorthWind Orders表提取7个指定的字段。
< SCRIPT LANGUAGE=VBScript RUNAT=Server >
Sub Application_OnStart
Application("Conn") = "Provider=SQLOLEDB; " & _
"Server=MyServer; " & _
"uid=sa; " & _
"pwd=;" & _
"DATABASE=northwind"
Application("SQL") = "SELECTTOP 0OrderID, " & _
"CustomerID, " & _
"EmployeeID, " & _
"OrderDate, " & _
"RequiredDate, " & _
"ShippedDate, " & _
"Freight " & _
"FROM[Orders] "
End Sub
< /SCRIPT >
'alternate sql - 25 records
Application("SQL") = "SELECTTOP 25OrderID, " & _
"CustomerID, " & _
"EmployeeID, " & _
"OrderDate, " & _
"RequiredDate, " & _
"ShippedDate, " & _
"Freight " & _
"FROM[Orders] "
'alternate sql - 250 records
Application("SQL") = "SELECTTOP 250 OrderID, " & _
"CustomerID, " & _
"EmployeeID, " & _
"OrderDate, " & _
"RequiredDate, " & _
"ShippedDate, " & _
"Freight " & _
"FROM[Orders] "
测试服务器配置如下:450 Mhz Pentium,512 MB RAM,NT Server 4.0 SP5,MDAC 2.1(数据访问组件),以及5.0版本的Microsoft脚本引擎。SQL Server运行在另外一台具有类似配置的机器上。和第一部分一样,我们仍旧使用Microsoft Web Application Stress Tool 记录从第一个页面请求到从服务器接收到最后一个字节的时间(TTLB,Time To Last Byte),时间以毫秒为单位。测试脚本调用每个页面1300次以上,运行时间约20小时,以下显示的时间是会话的平均TTLB。请记住,和第一部分一样,我们只关心代码的效率,而不是它的可伸缩性或服务器性能。
同时请注意我们启用了服务器的缓冲。另外,为了让所有的文件名字长度相同,有的文件名字中嵌入了一个或多个下划线。
三、第一次测试
在第一次测试中,我们模拟Microsoft ASP ADO示例中可找到的典型情形提取一个记录集。在这个例子(ADO__01.asp)中,我们首先打开一个连接,然后创建记录集对象。当然,这里的脚本按照本文第一部分所总结的编码规则作了优化。
< % Option Explicit % >
< !-- #Include file="ADOVBS.INC" -- >
< %
Dim objConn
Dim objRS
Response.Write( _
"< HTML >< HEAD >" & _
"< TITLE >ADO Test< /TITLE >" & _
"< /HEAD >< BODY >" _
)
Set objConn = Server.CreateObject("ADODB.Connection")
objConn.Open Application("Conn")
Set objRS = Server.CreateObject("ADODB.Recordset")
objRS.ActiveConnection = objConn
objRS.CursorType = adOpenForwardOnly
objRS.LockType = adLockReadOnly
objRS.Open Application("SQL")
If objRS.EOF Then
Response.Write("No Records Found")
Else
'write headings
Response.Write( _
"< TABLE BORDER=1 >" & _
"< TR >" & _
"< TH >OrderID< /TH >" & _
"< TH >CustomerID< /TH >" & _
"< TH >EmployeeID< /TH >" & _
"< TH >OrderDate< /TH >" & _
"< TH >RequiredDate< /TH >" & _
"< TH >ShippedDate< /TH >" & _
"< TH >Freight< /TH >" & _
"< /TR >" _
)
'write data
Do While Not objRS.EOF
Response.Write( _
"< TR >" & _
"< TD >" & objRS("OrderID") & "< /TD >" & _
"< TD >" & objRS("CustomerID") & "< /TD >" & _
"< TD >" & objRS("