飘易博客(作者:Flymorn)
订阅《飘易博客》RSS,第一时间查看最新文章!
飘易首页 | 留言本 | 关于我 | 订阅Feed

ASP的高效率的分页算法

Author:Flymorn Source:飘易博客
Categories:Asp编程 PostTime:2008-10-14 19:11:02
正 文:
    写程序也这么长的时间了,对于程序分页算法也有所接触。飘易一般习惯使用的有两种分页算法,一是传统的ADO分页,二是SELECT TOP分页算法。对于小型数据表,比如一两万的数据量的表,我倾向使用ADO算法,对于大型的数据表,则必须采用后者的算法了。

    先来说说传统的ADO分页算法。

    这种算法,使用起来简单容易,很容易上手,对于小心数据库来说是首选,其执行效率很高,数据库自带的游标功能进行翻页的时候也很方便。

    其通常使用的代码如下:
<%
dim recordcountnum,page,i,j
listnum = "30"  '每页显示记录数
sql="select id,title,time from table1 order by time desc"
Set rs = Server.CreateObject ("ADODB.Recordset")
rs.Open sql,conn,1,1
If rs.eof and rs.bof Then 
Else
recordcountnum=Rs.recordcount
Rs.pagesize = listnum  
page = Request("page")
If  page = "" or page < 1 Then
page=1
End If
If (page-Rs.pagecount) > 0 Then
page=Rs.pagecount
End If
Rs.absolutepage=page
j=rs.recordcount
j=j-(page-1)*listnum
i=0
Do While Not rs.Eof and i<listnum
response.write "每条记录信息:"&rs("id")&"<br>"
i=i+1
rs.movenext
loop
''翻页代码略……
%>

    这种ADO游标的分页算法,由于每次加载页面都要重新读取数据表的全部数据,虽然游标的使用非常简单,当数据表容量不大的情况下,也是可以使用的;但当数据量非常大的情况下,使用这种分页方法的效率无疑是极低的。

     所以,我们需要引入另外一种高效的SELECT TOP分页算法。代码如下:


<%
'每页的记录数
dim pagesize
pagesize= "30"

'读出总记录数,总页数,飘易注
Dim TotalRecords,TotalPages
SQLstr="Select count(id) As RecordSum From table1" 
Set Rs=conn.Execute(SQLstr,0,1) 
TotalRecords=Rs("RecordSum") 
if Int(TotalRecords/pagesize)=TotalRecords/pagesize then
TotalPages=TotalRecords/pagesize
else
TotalPages=Int(TotalRecords/pagesize)+1
end if
Rs.Close 
Set Rs=Nothing 

'当前页码,飘易注
dim page
page=Request("page")
if isnumeric(page)=false then
response.write "<SCRIPT language=JavaScript>alert('参数错误!');"
response.write "window.close();</SCRIPT>"
response.end
end if
If page="" or page<1 Then page=1
If page-TotalPages>0 Then page=TotalPages
page=int(page)

if page=1 then
sql="select top "&pagesize&" id,title,time from table1 order by time desc"
else
sql="select top "&pagesize&" id,title,time from table1 where time<(SELECT Min(time) FROM (SELECT TOP "&pagesize*(page-1)&" time FROM table1 ORDER BY time desc) AS T) order by time desc"
end if
Set rs = Server.CreateObject ("ADODB.Recordset")
rs.Open sql,conn,1,1
Do While Not rs.Eof
response.write "每条记录信息:"&rs("id")&"<br>"
rs.movenext
loop
rs.close
set rs=nothing
''翻页代码省略……
%>

    这是一种非常高效的分页算法。当数据表中的数据量成百上千万的时候,上面的这种分页算法的响应时间是非常短的,通常在几十毫秒之内。原理很简单,就是每次分页,我只取需要的几十条记录而已,使用SELECT TOP也正是基于这样的考虑。

    上面的两个分页算法的例子中,flymorn都使用了时间字段time来进行order by排序,因为在我接触的绝大多数系统中,我们都需要把用户最近更新(包括新添加的记录以及新修改过的老记录)的内容展示在前面,如果仅仅使用自动编号的ID作为排序字段的话,用户编辑过的老信息将无法展示在前面。这就是flymorn使用时间字段的原因了。

    这里又涉及到聚合索引的问题了。默认情况下,我们是以自动编号ID作为主键,并且用作聚合索引列,如果上面的算法中,使用这样的ID列来排序的话,效率会更高,数据库响应的时间会更少;然而,我提到了最近更新的内容需要展示在前面的问题,所以,我们必须使用时间字段来排序。因此,为了更高的分页效率,我们可以在数据库设计的时候,把这个时间字段设计为聚合索引列。

    通过这样的设计后,整个分页效率就会得到非常高的提高了。

    然而,把这个时间字段作为聚合索引列,存在又一个小问题。因为数据表在排列数据的时候,是按照聚合索引列来进行物理排序的,当用户添加数据的时候,没有什么问题,在数据表的末尾添加就行了;当用户编辑信息的时候,数据库需要根据这个聚合索引列,把刚编辑过的信息也提到表的末尾,这里就需要耗费一定的时间了。就是说,当我们以时间字段为聚合索引列的时候,我们就需要在 UPDATE 数据的时候多耗费一点的时间。

    然而,综合比较而言,飘易认为,SELECT TOP的高效分页算法的关键是要避免全表扫描,尽量只获取需要的字段,排序的字段最好是聚合索引列,实践表明,以聚合索引列来排序的SQL语句的响应时间是最快的。这样处理之后,对于SQL SERVER数据库来说,即使上千万的数据量,也不用怕分页算法失去响应了。

    上面是以 ASP 语言为例写的算法,当然同样可以改造成其他的如ASP.NET,PHP语言所使用。为了更好的使用这样的分页代码,大家也可以把上面的算法改写成存储过程。

    最后,留一个小问题:SELECT TOP分页的时候,当翻页到最后的时候,如果排序字段列不是聚合索引列的时候,程序的响应时间会如何呢?
作者:Flymorn
来源:飘易博客
版权所有。转载时必须以链接形式注明作者和原始出处及本声明。
上一篇:微软10月20号反盗版Windows XP:一小时黑屏一次
下一篇:WHERE条件中or与union引起的全表扫描的问题
8条评论 “ASP的高效率的分页算法”
1 Fufu
2008-10-30 13:30:47
说得不错,经验之谈。
2 feng_sundy
2009-7-30 13:48:40
top 分页,其实没有什么用,这样排序会失去作用。如果只是用主键和聚合索引倒是可以。局限性太大。现在的列表都需要多列排序,不可能把每列都设置成聚合索引。
3 flymorn
2009-7-30 16:22:44
To: feng_sundy,
如果排序需要比较多列的话,那么是否应该考虑数据库结构是否合理呢?我们应该避开多列同时进行比较,这样的做法无疑是极低效率的……
4 正在研究
2010-8-3 12:30:02
请问用top分页真的效率吗?
5 bobo
2010-10-10 14:24:35
请问楼主 :如果是搜索关键词页面 怎么分页呢
6 呵呵
2010-10-17 11:21:42
如果字段上有重复值的话你这个分页就不准了。但是字段上有索引的话这个排序的效率还是可以的,这种方法其实就是max id方法。如果排序字段不止一个的话就不行了,但是这种情况还是存在的。这样可以使用颠倒top,但是效率要慢一些,越往后越慢,如果能结合半分的话那就是两头快中间慢。把各种方法结合起来,根据不同的情况灵活选用,应该还是不错的。
2010-12-24 13:39:19
top分页不能排序,让我狂抓了一晚,害死了
8 yzp
2012-7-17 9:56:22
你这个分页局限性太多了,现在做网站都要在数据库加个排序字段的,以方便用户把某个数据放在前面,排序字段可以重复值的,你这个分页就根本不行。
发表评论
名称(*必填)
邮件(选填)
网站(选填)

记住我,下次回复时不用重新输入个人信息
© 2007-2010 飘易博客 Www.Piaoyi.Org 原创文章版权由飘易所有 渝ICP备07006361号