为了找到一种高效率的翻页方法,我分析了常见的几种ADO页定位方法,发现在翻页前都要利用查询语句把符合条件的纪录读出,放入RecordSet集合,然后再进行翻页的计算和操作。如果符合条件的纪录数大于你设定的每页显示纪录数,则多出来的纪录虽然已经读出但却没有用上,在翻到下一页时,又重新查询数据库。也就是说,如果你找到符合要求的500条纪录,查询时读出了500条纪录,但每页只显示20条纪录,这就有480条纪录读出后没用,翻页时又重复上述操作。众所周知,从数据源读取数据的操作是很费时间的,更何况读出来的数据大部份用不上呢?于是,我想如果每次只读出符合条件的、数量不超过每页显示条数的纪录应该是效率最高的,顺着这个思路又考虑到翻页所必需的条件,就产生了记住每页两端的记录号、翻页时只从端点读取每页显示条数的分页方法。
由于接触ASP的时间不长,从思路到实现还有一段距离,故在一个论坛中提出了这个想法与大家讨论,经过该论坛版主和网友们的分析、建议和指教逐步完成了这段代码,在我的老PII机器上进行检测,效果比较明显。在此特详细思路、解决办法、代码贴出请各位高人指教。
一、原则
1.每次刷新页面时根据翻页的方向,只读取自id1或id2开始的rows条纪录。
2.显示查询结果时用for/next循环,不用where not rs.eof and i<=rows/loop循环,目的是在循环时不检验rs.eof以提高速度。
3.当纪录的序号不连续时也能正常完成翻页功能。
二、方法
1.数据表中建立一个自动编号字段ID用以识别纪录号。
2.第一次查询时读出所有符合条件的纪录,用以计算有多少页(max)和多少条纪录(num),以后查询时每次只读出rows条纪录,并且不做重复计算。
3.用sql语句的TOP rows格式来读出所需要的数据,翻页的主要工作在这里完成。
4.向前翻页时用降序排序的方法实现。
5.用url转移时带上每页的页号、两端的端点号、最大页数、最大纪录数。
开始写代码的时候用过复合查询、升序排序等种种办法,结果均不理想,翻页经常翻到岔路上去,主要问题是如果用where ID<id1 则数据是从ID=0开始的rows条纪录,直接显示了第一页,没有达到向前翻页的目的;如果用降序排序,则数据是从ID<=id1开始的,但向后翻页的端点id2<id1,造成了混乱。当时直埋怨作系统的为何不来个Bottom N或Last N之类的指令,那就简单多了。试了几次后突然想到一个笨办法:既然是降序排序,在显示的时候反过来循环不就一切正常了?看来最简单的办法也可能是最有效的办法。另外,我认为除了用记忆端点分页的可以提高效率外,程序是否精炼,也会影响到速度。
这段代码没有考虑页面跳转的功能,我想除了论坛以外,如果是资料查询检索,页面跳转的用处不大,尤其是向后跳转。至于向前跳转,在代码中加入一些指令实现起来不难。
三、代码
------- 读取数据部分 -----------
id1,id2 - 页端点号,sn - 当前页号,sp - 上一页号, rows - 每页显示条数,go - 翻页方向(* 表示向回翻),max - 合计页数,num - 合计纪录数
dim id1,id2,sn,rows,go,sql,max,num
sql="select * from 数据表 where 查询条件"
go=request("go")
sn=1
rows=10
id1=request("id1")
if id1<>"" then
sql=left(sql,6)&" top "&rows&right(sql,len(sql)-6)
if go="*" then
sn=request("sp")-1
sql=sql & " and ID<"&id1&" order by ID desc"
else
sn=request("sp")+1
id2=request("id2")
sql=sql & " and ID>"&id2
end if
end if
Set Rs=server.createobject("ADODB.Recordset")
Rs.open sql,conn,3,1
if Rs.eof or Rs.bof then 提示没有纪录并返回
------- 计算部分 -----------
if id1="" then
num=Rs.recordcount
max=int(num/rows+0.99)
if max<1 then
rows=num
max=1
end if
else
max=int(request("m"))
num=request("n")
end if
------- 显示子程序 -----------
sub show(i)
response.write 显示的内容
end sub
%>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=gb2312">
<title>test</title>
</head>
------- 数据显示部份 -----------
<body>
<div>
<p>有【<%=num%>】条信息,第 <%=sn%> 页 共 <%=max%> 页</p>
<hr size="1">
<ul>
<%
m=num-((sn-1)*rows)
if m>rows then m=rows
if go="*" then
Rs.movelast
id1=Rs("ID")
for i=1 to m
show(i)
Rs.moveprevious
next
Rs.movenext
else
Rs.movefirst
id1=Rs("ID")
for i=1 to m
show(i)
Rs.movenext
next
Rs.moveprevious
end if
id2=Rs("ID")
surl="test.asp?sp="&sn&"&m="&max&"&n="&num&"&id1="&id1&"&id2="&id2
rs.close
set rs=nothing
conn.close
set conn=nothing
</ul>
<hr size="1">
<table cellpadding="0" cellspacing="0" width="100%">
<tr>
<td width="80%"></td>
<td width="10%"><%if sn>1 then response.write "<a href='"&surl&"&go=*'>上一页</a>"%>
</td>
<td width="10%"><%if sn<max then response.write "<a href='"&surl&"'>下一页</a>"%>
</td>
</tr>
</table>
</div>
</body>
</html>
四、测试对比
5万条纪录的Access数据库(大小为26.2M),用了几种方法分别进行运行时间测试,结果如下:
------------------------------------------
页号 |ADO页定位|Bookmark|list.asp|记忆端点
------------------------------------------
1 10.66 10.98 10.71 9.71
2 6.59 7.48 6.70 0.66
3 6.42 7.73 6.58 0.27
4 6.53 7.68 6.48 0.27
5 6.37 7.68 6.60 0.33
6 6.65 7.52 6.58 0.33
7 6.41 7.53 6.49 0.27
8 6.36 8.19 6.64 0.27
9 6.31 7.85 6.54 0.33
10 6.43 7.58 6.53 0.33
11 6.48 7.57 6.53 0.33
10 6.43 7.53 6.63 0.38
9 6.54 7.64 6.53 0.33
8 6.41 7.57 6.58 0.33
7 6.42 7.68 6.53 0.32
6 6.42 7.57 6.48 0.33
5 6.41 7.65 6.63 0.27
4 6.37 7.62 6.48 0.33
3 6.48 7.59 6.47 0.32
2 6.75 7.60 6.52 0.28
1 6.53 7.61 6.48 0.32
------------------------------------------
list.asp是论坛中ywd1520朋友提供的从动网里分离出来的分页程序,bookmark是某版主朋友提供的分页程序,时间单位:秒。
测试环境:
清除所有缓存文件,用相同的页面和查询条件,检索出5万条符合要求的纪录,顺序翻页,先向后再向前。每页10条纪录,每条纪录4个字段。
硬件配置:PII350超外频至133M使用,256M SDRAM内存,5.1G昆腾硬盘
操作系统:WinMe, PWS, MS Access2000
盼各位高人指教,谢谢。