首 页 网络编程
网页制作 图形图象 操作系统 冲浪宝典
软件教学 认证考试

网络安全 网络办公 行业资讯 评测对比
您当前位置:站长天空 -> 网络安全-> 教你一招
最佳的数据库分页方法-ASP教程,数据库相关
作者:网友供稿 点击:295
推荐
西部数码-全国虚拟主机10强!20余项虚拟主机管理功能,全国领先!第6代双线路虚拟主机,南北访问畅通无阻!可在线rar解压,自动数据恢复设置虚拟目录等.免费赠送访问统计,企业邮局.Cn域名注册10元/年,自助建站480元起,免费试用7天,满意再付款!P4主机租用799元/月.月付免压金
站内搜索
文章页数:[1] 
一:一个老生常谈的问题。
    我们知道,记录集分页是数据库处理中十分常见的问题。而当我们设计到网络数据库,就是说要考虑传输带宽问题时,分页问题就每每困扰着每一个数据库程序设计人员。

二:分页问题的解决方案汇总
    说起解决的方案,每个数据库设计人员可能都会举出许多方法。但细分后,可以归为三类。一: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游标分页效率要好的多。

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

文章整理:站长天空 网址:http://www.z6688.com/
以上信息与文章正文是不可分割的一部分,如果您要转载本文章,请保留以上信息,谢谢!

文章页数:[1] 


放大字体显示 缩小字体显示 打印文章 推荐给朋友
热门文章
·Java 中开源的CMS系统-JSP教程,Java技巧及代码
·ASP.NET服务器控件发送脚本-ASP教程,远程脚本
·javaCC学习笔记-JSP教程,Java技巧及代码
·asp.net中的模态对话框-ASP教程,ASP应用
·在.net应用程序中使用用户控件-.NET教程,组件控件开发
·身份证15位转换成18位代码(vbscript)-ASP教程,脚本编码
·基于dsp控制的数字式双向dc/dc变换器的实现
·利用Asp.net 动态创建DataList-ASP教程,ASP应用
·最佳的数据库分页方法-ASP教程,数据库相关
·利用JAVA技术进行XML编程(第一部分)-JSP教程,Java与XML
最新文章
·网关防护做得好web威胁少一半_教你一招教程
·计算机安全十大建议_教你一招教程
·给ie加个参数 永远不怕ie主页被修改_教你一招教程
·修改十四项设置 打造安全牢靠易用电脑_教你一招教程
·论垂直搜索引擎存在的意义_站长心得
·简单分析个人网站最缺少的几点要素_站长心得
·个人网站赢利探讨:网站究竟是如何盈利的?_站长心得
·网站设计的思考网页版面布局的原理_站长心得
·建立用自己域名结尾的hotmail邮箱2_站长心得
·随时保障系统安全五步搞定补丁管理部署_教你一招教程
相关主题
西部数码虚拟主机

友情链接
CNNIC 西部数码
万网 自助建站
虚拟主机 asp空间
域名注册 域名
域名申请 主页空间
论坛空间 网站空间
国际域名 虚拟空间
空间租用 DDOS防火墙
成都主机托管 四川主机托管
主机租用 服务器租用
网站目录 自助建站
虚拟主机 网址大全
软件下载
自助链接
虚拟主机资讯 特价虚拟主机
版权申明:本站文章均来自网络,如有侵权,请联系我们,我们收到后立即删除,谢谢!
关于我们:站长天空:专业提供最新的站长资讯、在线教程、虚拟主机权威评测、虚拟主机性能对比、网站制作教程,开发教程,站长工具。包括网页制作教程、冲浪宝典、编程参考、操作系统、软件教学、行业动态等。
特别注意:本站所有转载文章言论不代表本站观点,本站所提供的摄影照片,插画,设计作品,如需使用,请与原作者联系,版权归原作者所有。
发表评论 打印  刷新     关闭