欢迎光临
我们一直在努力

最佳的数据库分页方法-ASP教程,数据库相关

建站超值云服务器,限时71元/月

一:一个老生常谈的问题。

    我们知道,记录集分页是数据库处理中十分常见的问题。而当我们设计到网络数据库,就是说要考虑传输带宽问题时,分页问题就每每困扰着每一个数据库程序设计人员。

二:分页问题的解决方案汇总

    说起解决的方案,每个数据库设计人员可能都会举出许多方法。但细分后,可以归为三类。一:ado纪录集分页、二:专储记录集分页、三、数据库游标分页。

 一:著名的ado纪录集分页。

     说到著名,因为这个可能是最简单和常见的分页方法了。(可能也是用的最多的)就是利用ado自带的分页功能来实现分页。

     具体流程为,数据库根据查询语句返回一个完整的纪录集。然后到客户端后有客户端的游标进行分页。他们大多数由ado自带的recordset对象就可以实现了。可能涉及到的属性有:

recordset.pagesize:每页输出纪录集的大小

recordset.absolutepage: 当前输出的页    (有以上的两个属性其实就可以完成分页输出了)

recordset.pagecount: 目前的总页数。

     这种方法好不好呢,有的人说是十分好,也有人说效率不高。其实这的根据实际的应用状况来确定,如果是单机数据库,或者是局域网环境,或者数据库纪录较少,则他都是很好的分页方法,而且如果不涉及到网络和更新较少的环境里,则他可以说是最好的分页方法。因为它可以先生成一个缓存记录集,以后的几页纪录都可以不通过数据库来取即可。但是,如果涉及到网络,或者是更新频繁。他就不是很实用的了。

列举程序。(我们都用网络问题来考虑)

 

nowpage=request("nowpage") 当前的输出页

if nowpage="" or nowpage<1 then nowpage=1

set rs=server.createobject("adodb.recordset")

rs.cursortype=1

sql="select * from table1 "

rs.open sql,strconn (strconn为连接字段,已定义过)

rs.pagesize=20  当前页的大小

if cint(nowpage)>rs.pagecount then nowpage=rs.pagecount

rs.absolutepage=nowpage

然后输出当前一页的纪录

………….

还可以提供一下程序属性设置。

首页:nowpage=1

前页:nowpage=nowpage-1

下页:nowpage=nowpage+1

尾页:nowpage=rs.pagecount

总纪录数:rs.recordcount

总页数:rs.pagecount

二:转储纪录集分页。

这种方法诞生于网络时代,就是利用服务器端的强大处理过程,先将目标数据库存到一个临时的数据库里,并且加上一个自增字段来进行划分页面,最后将所需固定数目的纪录集传回。

优点是:只需交互一次,而且返回固定一页的纪录集。

缺点是:如果纪录集增大时则每次都需建立一个临时纪录集,也比较耗时间,但减少了网络传输量。

例子:



取自 worx 英文版的<<professional active server pages 3.0>>

isbn1861002610

关键地方我已作了中文翻译



create procedure usp_pagedauthors

@ipage int,

@ipagesize int

as

begin

– disable row counts

set nocount on

– declare variables

declare @istart int – start record

declare @iend int – end record

declare @ipagecount int – total number of pages

– create the temporary table

       –建立临时表。

create table #pagedauthors        (

–这个自增字段十分关键,就是靠他来完成分页标示。

id int identity,      

au_id varchar(11) not null ,

au_lname varchar(40) not null ,

au_fname varchar(20) not null ,

phone char(12) not null ,

address varchar(40) null ,

city varchar(20) null ,

state char(2) null ,

zip char(5) null ,

contract bit not null 

)

– populate the temporary table       

–先转存到上面的这个纪录集。

insert into #pagedauthors (au_id, au_lname, au_fname, 

phone, address, city, state, zip, contract)

select au_id, au_lname, au_fname, 

phone, address, city, state, zip, contract

from authors

– work out how many pages there are in total

select @ipagecount = count(*)

from  authors

select @ipagecount = ceiling(@ipagecount / @ipagesize) + 1

– check the page number

if @ipage < 1

select @ipage = 1

if @ipage > @ipagecount

select @ipage = @ipagecount

– calculate the start and end records

select @istart = (@ipage - 1) * @ipagesize

select @iend = @istart + @ipagesize + 1

– select only those records that fall within our page

–这条sql语句就是选取固定的纪录集。

select au_id, au_lname, au_fname, 

phone, address, city, state, zip, contract

from #pagedauthors

where id > @istart

and id < @iend

drop table #pagedauthors

– turn back on record counts

set nocount off

– return the number of records left

return @ipagecount

end

而输出端可以用最快类型的ado"火线光标"顺次输出就可

<%

  dim cmdauthors

  dim rsdata

  dim ipage

  dim ilastpage

  dim squote

  squote = chr(34)

  get the requested data

  if request.querystring("page") = "" then

    ipage = 1

  else

    ipage = cint(request.querystring("page"))

    if ipage < 1 then

      ipage = 1

    end if

  end if

   create the objects

  set cmdauthors = server.createobject("adodb.command")

  set rsauthors = server.createobject("adodb.recordset")

  with cmdauthors

    .activeconnection = strconn

    .commandtext = "usp_pagedauthors"

    .commandtype = adcmdstoredproc

    .parameters.append .createparameter("return_value", adinteger, _

                              adparamreturnvalue)

    .parameters.append .createparameter("@ipage", adinteger, _

                              adparaminput, 8, ipage)

    .parameters.append .createparameter("@ipagesize", adinteger, _

                              adparaminput, 8, 10)

    set rsdata = .execute

  end with

   create the table

   start building the table

  response.write "<table border=1><thead><tr>"

  for each fldf in rsdata.fields

    response.write "<td>" & fldf.name & "</td>"

  next

  response.write "</tr></thead><tbody>"

   now loop through the records

  while not rsdata.eof

    response.write "<tr>"

    for each fldf in rsdata.fields

      response.write "<td>" & fldf.value & "</td>"

    next

    response.write "</tr>"

    rsdata.movenext

  wend

  response.write "</tbody></thead></table><p>"

   now some paging controls

  sme = request.servervariables("script_name")

  response.write " <a href=" & squote & sme & "?page=1" & squote & ">first page</a>"

   close the recordset and extract the number of records left

  rsdata.close

  ilastpage = cmdauthors.parameters("return_value")

   only give an active previous page if there are previous pages

  if ipage <= 1 then

    response.write " <span>previous page</span>"

  else

    response.write " <a href=" & squote & sme & "?page=" & ipage - 1 & squote & ">previous page</a>"

  end if

   only give an active next page if there are more pages

  if ilastpage = ipage then

    response.write " <span>next page</span>"

  else

    response.write " <a href=" & squote & sme & "?page=" & ipage + 1 &  squote & ">next page</a>"

  end if

  response.write " <a href=" & squote & sme & "?page=" & ilastpage & squote & ">last page</a>"

   clean up

  set rsdata = nothing

  set cmdauthors = nothing

%>

第三种方法:服务器端游表选取纪录集的办法。

    这种办法属于很有争论的办法。

    它主要是用服务器端的游表选取纪录集,然后一次返回,也就是返回多个纪录集,每个纪录集就有一个纪录。然后用recordset.nextrecord的方法来输出每一个纪录集。

    国外许多网站对此进行过考证,因为第一:recordset.nextrecord具有这种方法的ado.游表不是最快的火线游表,第二,许多人认为采用recordset.nextrecord方法输出时其实等于和服务器端交互了一次,所以这种方法属于那种当许多人并发访问数据库时,能导致数据库访问量成倍增。。。 

             

列举程序:(作者:bigeagle)

if exists(select * from sysobjects where id = object_id("up_topiclist"))

   drop proc up_topiclist

go

create proc up_topiclist 

            @a_forumid int , @a_intdays int , @a_intpageno int , @a_intpagesize tinyint

   as

       declare @m_intrecordnumber int

       declare @m_intstartrecord  int

       select @m_intrecordnumber = @a_intpagesize * @a_intpageno

       select @m_intstartrecord = @a_intpagesize * (@a_intpageno - 1) + 1

       if @a_intdays = 0                      –如果不限定天数

          begin

                /*求符合条件记录数*/

                select "recordcount" = count(*)                         

                       from bbs where layer=1 and forumid = @a_forumid 

               /*输出纪录*/

               /*首先定义可滚动光标*/

               set rowcount @m_intrecordnumber

               declare m_curtemp scroll cursor 

                       for

                          select a.id ,a.title , d.username , a.faceid ,

                                contentsize = datalength(a.content) , 

                                totalchilds = (select sum(totalchilds) 

                                                        from bbs as b 

                                                        where a.rootid = b.rootid) ,

                                lastreplytime = (select max(posttime) 

                                                          from bbs as c 

                                                          where a.rootid = c.rootid)

                                from bbs as a 

                                     join bbsuser as d on a.userid = d.id 

                                where layer=1 and forumid = @a_forumid 

                                order by rootid desc , layer , posttime

               open m_curtemp

               fetch absolute @m_intstartrecord from m_curtemp

               while  @@fetch_status = 0 

                      fetch next from m_curtemp

               set rowcount 0 

               /*清场*/       

               close m_curtemp

               deallocate m_curtemp

          end                      

                          

       else                                –如果限定天数          

          begin

                /*求符合条件记录数*/

                select "recordcount" = count(*)                         

                       from bbs where layer=1 and forumid = @a_forumid 

                                      and dateadd(day , @a_intdays , posttime) > getdate() 

               /*输出纪录*/

               /*首先定义可滚动光标*/

               set rowcount @m_intrecordnumber

               declare m_curtemp scroll cursor 

                       for

                          select a.id ,a.title , d.username , a.faceid ,

                                contentsize = datalength(a.content) , 

                                totalchilds = (select sum(totalchilds) 

                                                        from bbs as b 

                                                        where a.rootid = b.rootid) ,

                                lastreplytime = (select max(posttime) 

                                                          from bbs as c 

                                                          where a.rootid = c.rootid)

                                from bbs as a 

                                     join bbsuser as d on a.userid = d.id 

                                where layer=1 and forumid = @a_forumid 

                                      and dateadd(day , @a_intdays , posttime) > getdate() 

                                order by rootid desc , layer , posttime

               open m_curtemp

               fetch absolute @m_intstartrecord from m_curtemp

               while  @@fetch_status = 0 

                      fetch next from m_curtemp

               set rowcount 0 

               /*清场*/       

               close m_curtemp

               deallocate m_curtemp

          end                                                

go

注:若在asp中调用存储过程的command对象为cm,则set rs=cm.execute,然后用set rs=rs.nextrecordset取下一条记录。

三:测试结果。

看到了这么多的分页方法。那么那种最好呢,最好的分页方法是什么呢?

还是做个测试吧。

测试工具:microsoft web application stress tool 1.1

测试平台:win2000 server 中文版 + iis5.0 + sql server 7.0

数据纪录:8000条  (非相同的股票历史纪录集)

模拟环境:56k model / 2m专线 / 10兆专线 

测试次数:3次

测试结果:服务器游标 >== 存储过程分页 > > ado分页 

(符号 >== :表示基本上相同,但有时稍大, 符号:> > 远远大于 )

看来,前两者差别不大,而且在多纪录集时,服务器端游标比存储过程稍大一些。但都比ado游标分页效率要好的多。

那么什么是最好的分页方法呢,我们理想的分页方法是什么呢?

其实就是:客户端传递一个页码过去,然后服务器端直接通过一次查询就生成所需的一页的记录集,并且以一个纪录集的形式返回给客户端。那么这种放法有没有呢?我可以告诉大家,有,而且经过我的测试,确实是效率最好的一种方法。下次我们就谈谈这种理论上最好的分页方法。。。。。。。。。

赞(0)
版权申明:本站文章部分自网络,如有侵权,请联系:west999com@outlook.com 特别注意:本站所有转载文章言论不代表本站观点! 本站所提供的图片等素材,版权归原作者所有,如需使用,请与原作者联系。未经允许不得转载:IDC资讯中心 » 最佳的数据库分页方法-ASP教程,数据库相关
分享到: 更多 (0)

相关推荐

  • 暂无文章