十、用哪种方法引用记录集字段值效率最高?
10.1 测试
至此为止我们一直通过名字引用记录集中的字段值。由于这种方法要求每次都必须寻找相应的字段,它的效率并不高。为证明这一点,下面这个测试中我们通过字段在集合中的索引引用它的值(ado__08.asp):
write data
do while not objrs.eof
response.write( _
"< tr >" & _
"< td >" & objrs(0) & "< /td >" & _
"< td >" & objrs(1) & "< /td >" & _
"< td >" & objrs(2) & "< /td >" & _
"< td >" & objrs(3) & "< /td >" & _
"< td >" & objrs(4) & "< /td >" & _
"< td >" & objrs(5) & "< /td >" & _
"< td >" & objrs(6) & "< /td >" & _
"< /tr > " _
)
objrs.movenext
loop
和预期的一样,页面开销也有小小的变化(这或许是因为代码略有减少)。然而,这种方法在显示时间上的改善是相当明显的。
在下一个测试中,我们把所有的字段分别绑定到变量(ado__09.asp):
if objrs.eof then
response.write("no records found")
else
write headings
…
dim fld0
dim fld1
dim fld2
dim fld3
dim fld4
dim fld5
dim fld6
set fld0 = objrs(0)
set fld1 = objrs(1)
set fld2 = objrs(2)
set fld3 = objrs(3)
set fld4 = objrs(4)
set fld5 = objrs(5)
set fld6 = objrs(6)
write data
do while not objrs.eof
response.write( _
"< tr >" & _
"< td >" & fld0 & "< /td >" & _
"< td >" & fld1 & "< /td >" & _
"< td >" & fld2 & "< /td >" & _
"< td >" & fld3 & "< /td >" & _
"< td >" & fld4 & "< /td >" & _
"< td >" & fld5 & "< /td >" & _
"< td >" & fld6 & "< /td >" & _
"< /tr >" _
)
objrs.movenext
loop
set fld0 = nothing
set fld1 = nothing
set fld2 = nothing
set fld3 = nothing
set fld4 = nothing
set fld5 = nothing
set fld6 = nothing
response.write("< /table >")
end if
这是目前为止最好的记录。请注意单个记录的显示时间已经降低到0.45毫秒以下。
上述脚本都要求对结果记录集的构造有所了解。例如,我们在列标题中直接使用了字段名字,单独地引用各个字段值。下面这个测试中,不仅字段数据通过遍历字段集合得到,而且字段标题也用同样的方式得到,这是一种更为动态的方案(ado__10.asp)。
if objrs.eof then
response.write("no records found")
else
write headings
response.write("< table border=1 >< tr >")
for each objfld in objrs.fields
response.write("< th >" & objfld.name & "< /th >")
next
response.write("< /tr >")
write data
do while not objrs.eof
response.write("< tr >")
for each objfld in objrs.fields
response.write("< td >" & objfld.value & "< /td >")
next
response.write("< /tr >")
objrs.movenext
loop
response.write("< /table >")
end if
可以看到,代码性能有所下降,但它仍旧要比ado__07.asp要快。
下一个测试示例是前面两个方法的折衷。我们将继续保持动态特征,同时通过在动态分配的数组中保存字段引用提高性能:
if objrs.eof then
response.write("no records found")
else
dim fldcount
fldcount = objrs.fields.count
dim fld()
redim fld(fldcount)
dim i
for i = 0 to fldcount-1
set fld(i) = objrs(i)
next
write headings
response.write("< table border=1 >< tr >")
for i = 0 to fldcount-1
response.write("< th >" & fld(i).name & "< /th >")
next
response.write("< /tr >")
write data
do while not objrs.eof
response.write("< tr >")
for i = 0 to fldcount-1
response.write("< td >" & fld(i) & "< /td >")
next
response.write("< /tr >")
objrs.movenext
loop
for i = 0 to fldcount-1
set fld(i) = nothing
next
response.write("< /table >")
end if
虽然还不能超过以前最好的成绩,但它比开头的几个示例要快,同时它具有动态地处理任何记录集这一优点。
与前面的测试代码相比,下面的测试代码有了根本性的改动。它使用记录集对象的getrows方法填充数组以供循环访问数据,而不是直接访问记录集本身。注意在调用getrows之后立即把recordset设置成了nothing,也就是尽快地释放了系统资源。另外,请注意数组的第一维代表字段,第二维代表行(ado__12.asp)。
if objrs.eof then
response.write("no records found")
objrs.close
set objrs = nothing
else
write headings
…
set array
dim arrrs
arrrs = objrs.getrows
close recordset early
objrs.close
set objrs = nothing
write data
dim numrows
dim numflds
dim row
dim fld
numflds = ubound(arrrs, 1)
numrows = ubound(arrrs, 2)
for row= 0 to numrows
response.write("< tr >")
for fld = 0 to numflds
response.write("< td >" & arrrs(fld, row) & "< /td >")
next
response.write("< /tr >")
next
response.write("< /table >")
end if
使用getrows方法时,整个记录集都被提取到了数组。虽然记录集极端庞大时可能产生资源问题,但是用循环访问数据的速度确实更快了,这是由于取消了movenext和检查eof之类的函数调用。
速度是要付出代价的,现在记录集的元数据已经丢失了。为解决这个问题,我们可以在调用getrows之前从记录集对象提取标题信息;此外,数据类型和其他信息也可以预先提取。另外还要注意的是,测试中性能上的优势只有在记录集较大的时候才会出现。
这一组的最后一个测试中,我们使用了记录集的getstring方法。getstring方法将整个记录集提取成为一个大的字符串,并允许指定分隔符(ado__13.asp):
if objrs.eof then
response.write("no records found")
objrs.close
set objrs = nothing
else
write headings
…
set array
dim strtable
strtable = objrs.getstring (2, , "< /td >< td >", "< /td >< /tr >< tr >< td >")
close recordset early
objrs.close
set objrs = nothing
response.write(strtable & "< /td >< /tr >< /table >")
end if
虽然这种方法在速度上的好处非常明显,但它只适用于最简单的操作,根本无法适应稍微复杂的数据操作要求。
10.2 意见
在进行这一组的测试之前,完成单个记录的时间徘徊在0.83毫秒左右,这组测试中的大多数结果使这个数字减半。其中某些测试实例具有无与伦比的性能表现,但这些代码损失了适应能力。
因此,我们得到的是下面几条较有价值的规则:
如果记录集中的数据不需要分别操作而且可以用一致的方式格式化,使用getstring方法提取数据。
如果要求有更灵活的格式,但不需要用到记录集的元数据,使用getrows将数据提取到数组。
如果要求有更灵活的格式,同时要用到记录集的元数据,在进入数据提取循环之前将字段绑定到变量。
始终避免通过名字引用字段。
