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

网络安全 网络办公 行业资讯 评测对比
您当前位置:站长天空 -> 网络编程-> Shell教程
DataGrid基于Access的快速分页法-.NET教程,数据库应用
作者:网友供稿 点击:201
推荐
西部数码-全国虚拟主机10强!20余项虚拟主机管理功能,全国领先!第6代双线路虚拟主机,南北访问畅通无阻!可在线rar解压,自动数据恢复设置虚拟目录等.免费赠送访问统计,企业邮局.Cn域名注册10元/年,自助建站480元起,免费试用7天,满意再付款!P4主机租用799元/月.月付免压金
站内搜索
文章页数:[1] 
datagrid是一个功能非常强大的asp.net web服务器端控件,它除了能够方便地按各种方式格式化显示表格中的数据,还可以对表格中的数据进行动态的排序、编辑和分页。使web开发人员从繁琐的代码中解放。实现datagrid的分页功能一直是很多初学asp.net的人感到棘手的问题,特别是自定义分页功能,实现方法多种多样,非常灵活。本文将向大家介绍一种datagird控件在access数据库下的快速分页法,帮助初学者掌握datagrid的分页技术。



目前的分页方法



datagrid内建的分页方法是使用诸如“select * from <table>”的sql语句从数据库表中取出所有的记录到dataset中,datagrid控件绑定到该dataset之后,它的自动分页功能会帮你从该dataset中筛选出当前分页的数据并显示出来,其他没有用的数据将被丢弃。



还有一种方法是使用自定义分页功能,先将datagrid的allowcustompaging属性设置为true,再利用dataadapter的fill方法将数据的筛选工作提前到填充dataset时,而不是让datagrid帮你筛选:



public int fill (

dataset dataset, //要填充的 dataset。

int startrecord, //从其开始的从零开始的记录号。

int maxrecords, //要检索的最大记录数。

string srctable //用于表映射的源表的名称。

);




该方法首先将来自查询处的结果填充到dataset中,再将不需要显示的数据丢弃。当然,自定义分页功能需要完成的事情还不止这些,本文将在后面详细介绍。



以上两种方法的工作原理都是先从数据库中取出所有的记录,然后筛选出有用的数据显示出来。可见,两种方法的效率基本上是一致的,因为它们在数据访问阶段并没有采取有效的措施来减少access对磁盘的访问次数。对于小数量的记录,这种开销可能是比较小的,如果针对大量数据的分页,开销将会非常巨大,从而导致分页的速度非常的慢。换句话说,就算每个datagrid分页面要显示的数据只是一个拥有几万条记录的数据库表的其中10条,每次datagrid进行分页时还是要从该表中取出所有的记录。



很多人已经意识到了这个问题,并提出了解决方法:用自定义分页,每次只从数据库中取出要显示的数据。这样,我们需要在sql语句上下功夫了。由于access不支持真正的存储过程,在编写分页算法上就没有sql server那么自由了。sql server可以在存储过程中利用临时表来实现高效率的分页算法,受到了广泛的采用。而对于access,我们必须想办法在一条sql语句内实现最高效的算法。



用一条sql语句取得某段数据的方法有好几种。算法不同,效率也就不同。我经过粗略的测试,发现效率最差的sql语句执行时耗费的时间大概是效率最高的sql语句的3倍!而且这个数值会随着记录总数的增加而增加。下面将介绍其中两条常用的sql语句。



为了方便接下来的讨论,我们先约定如下:



变量
说明
变量
说明

@pagesize
每页显示的记录总数
@middleindex
中间页的索引

@pagecount
分页总数
@lastindex
最后一页的索引

@recordcount
数据表的记录总数
@tablename
数据库表名称

@pageindex
当前页的索引
@primarykey
主键字段名称

@firstindex
第一页的索引
@queryfields
要查询的字段集




变量
定义

@pagecount
(int)math.ceiling((double)@recordcount / @pagesize)

@firstindex
0

@lastindex
@pagecount – 1

@middleindex
(int)math.ceiling((double)@pagecount / 2) – 1




先让我们看看效率最差的sql语句:



select top @pagesize * from @tablename

where @primarykey not in (

select top @pagesize*@pageindex @primarykey from @tablename

order by @primarykey asc

) order by @primarykey asc




这条sql语句慢就慢在not in这里,主select语句遍历的每个@primarykey的值都要跟子select语句的结果集中的每一个@primarykey的值进行比较,这样时间复杂度非常大。这里不得不提醒一下大家,平时编写sql语句时应该尽量避免使用not in语句,因为它往往会增加整个sql语句的时间复杂度。



另一种是使用了两个top和三个order by的sql语句,如下所示:



select * from (

select top @pagesize * from (

select top @pagesize*(@pageindex+1) * from @tablename

order by @primarykey asc

) tablea order by @primarykey desc

) tableb order by @primarykey asc




这条sql语句空间复杂度比较大。如果要显示的分页面刚好是最后一页,那么它的效率比直接select出所有的记录还要低。因此,对于分页算法,我们还应该具体情况具体分析,不能一概而论。下面将简单介绍一下相关概念,如果您对主键和索引非常熟悉,可以直接跳过。



有关主键和索引的概念



在 access中,一个表的主键(primary key,又称主索引)必然是唯一索引(unique index),它的值是不会重复的。除此之外,索引依据索引列的值进行排序,每个索引记录包含着一个指向它所引用的数据行的指针,这对order by的执行非常有帮助。我们可以利用主键这两个特点来实现对某条记录的定位,从而快速地取出某个分页上要显示的记录。



举个例子,假设主键字段为integer型,在数据库表中,记录的索引已经按主键字段的值升序排好(默认情况下),那么主键字段值为“11”的记录的索引,肯定刚好在值为“12”的记录的索引前面(假设数据库表中存在主键的值为“12”的记录)。如果主键字段不具备unique约束,数据库表中将有可能存在两个或两个以上主键字段的值为“11”的记录,这样就无法确定这些记录之间的前后位置了。



下面就让我们看看如何利用主键来进行数据的分段查询吧。



快速分页法的原理



其实该分页法是从其他方法衍生而来的。本人对原来的方法认真地分析,发现通过优化和改进可以非常有效地提高它的效率。原算法本身效率很高,但缺乏对具体问题的具体分析。同一个分页算法,可能在取第一页的数据时效率非常高,但是在取最后一页的数据时可能反而效率更低。



经过分析,我们可以把分页算法的效率状态分为四种情况:

(1)@pageindex <= @firstindex

(2)@firstindex < @pageindex <= @middleindex

(3)@middleindex < @pageindex < @lastindex

(4)@pageindex >= @lastindex



状态(1)和(4)分别表示第一页和最后一页。它们属于特殊情况,我们不必对其使用特殊算法,直接用top就可以解决了,不然会把问题复杂化,反而降低了效率。对于剩下的两种状态,如果分页总数为偶数,我们可以看作是从数据库表中删掉第一页和最后一页的记录,再把剩下的按前后位置平分为两部分,即前面的一部分,也就是状态(2),后面的为另一部分,也就是状态(3);如果分页总数为奇数,则属于中间页面的记录归于前面的部分。这四种状态分别对应着四组sql语句,每组sql语句由升序和降序两条sql语句组成。



下面是一个数据库表,左边第一列是虚拟的,不属于该数据库表结构的一部分,它表示相应记录所在的分页索引。该表将用于接下来的sql语句的举例中:



pageindex
itemid
productid
price

0
001
0011
$12

002
0011
$13

1
003
0012
$13

004
0012
$11

2
005
0013
$14

006
0013
$12

3
007
0011
$13

008
0012
$15

4
009
0013
$12

010
0013
$11




由表可得:@pagesize = 2,@recordcount = 10,@pagecount = 5



升序的sql语句



(1)@pageindex <= @firstindex



取第一页的数据是再简单不过了,我们只要用top @pagesize就可以取出第一页要显示的记录了。



select top @pagesize @queryfields

from @tablename

where @condition

order by @primarykey asc




(2)@firstindex < @pageindex <= @middleindex



把取数据表前半部分记录和取后半部分记录的sql语句分开写,可以有效地改善性能。后面我再详细解释这个原因。现在看看取前半部分记录的sql语句。先取出当前页之前的所有记录的主键值,再从中选出最大值,然后取出主键值大于该最大值的前@pagesize条记录。这里@primarykey的数据类型可以不是integer类型,char、varchar等其他类型照样可以。



select top @pagesize @queryfields

from @tablename

where @primarykey > (

select max(@primarykey) from (

select top @pagesize*@pageindex @primarykey

from @tablename

where @condition

order by @primarykey asc

) tablea

) where @condition

order by @primarykey asc




例如:@pageindex=1,红-->黄-->蓝







(3)@middleindex < @pageindex < @lastindex



接下来看看取数据库表中后半部分记录的sql语句。该语句跟前面的语句算法的原理是一样的,只是方法稍微不同。先取出当前页之后的所有记录的主键值,再从中选出最小值,然后取出主键值小于该最小值的前@pagesize条记录。



select * from (

select top @pagesize @queryfields

from @tablename

where @primarykey < (

select min(@primarykey) from (

select top (@recordcount-@pagesize*(@pageindex+1)) @primarykey

from @tablename

where @condition

order by @primarykey desc

) tablea

) where @condition

order by @primarykey desc

) tableb

order by @primarykey asc




之所以把取数据表前半部分记录和取后半部分记录的sql语句分开写,是因为使用取前半部分记录的sql语句时,当前页前面的记录数目随页数递增,而我们还要从这些记录中取出它们的主键字段的值再从中选出最大值。这样一来,分页速度将随着页数的增加而减慢。因此我没有这样做,而是在当前页索引大于中间页索引时(@middleindex < @pageindex)选用了分页速度随着页数的增加而加快的算法。由此可见,假设把所有分页面划分为前面、中间和后面三部分,则最前面和最后面的分页速度最快,最中间的分页速度最慢。



例如:@pageindex=3,红 --> 黄 --> 蓝







(4)@pageindex >= @lastindex



取最后一页的记录可以简单地使用类似状态(1)的做法:



select * from (

select top @pagesize @queryfields

from @tablename

where @condition

order by @primarykey desc

) tablea order by @primarykey asc




不过,这样产生的最后一页不一定是实际意义上的最后一页。因为最后一页的记录数未必刚好跟@pagesize相等,而上面的sql语句是直接取得倒数的@pagesize条记录。如果想要精确地取得最后一页的记录,应该在先计算出该页的记录数,作为top语句的条件:



select * from (

select top (@recordcount-@pagesize*@lastindex) @queryfields

from @tablename where @condition

order by @primarykey desc

) tablea order by @primarykey asc




降序的sql语句



降序的sql语句跟升序的大同小异,这里就不在罗嗦了j



(1)@pageindex <= @firstindex



select top @pagesize @queryfields

from @tablename

where @condition

order by @primarykey desc




(2)@firstindex < @pageindex <= @middleindex



select top @pagesize @queryfields

from @tablename

where @primarykey < (

select min(@primarykey) from (

select top @pagesize*@pageindex @primarykey

from @tablename

where @condition

order by @primarykey desc

) tablea

) where @condition

order by @primarykey desc




(3)@middleindex < @pageindex < @lastindex



select * from (

select top @pagesize @queryfields

from @tablename

where @primarykey > (

select max(@primarykey) from (

select top (@recordcount-@pagesize*(@pageindex+1)) @primarykey

from @tablename

where @condition

order by @primarykey asc

) tablea

) where @condition

order by @primarykey asc

) tableb order by @primarykey desc




(4)@pageindex >= @lastindex



select * from (

select top (@recordcount-@pagesize*@lastindex) @queryfields

from @tablename where @condition order by @primarykey asc

) tablea order by @primarykey desc




如何动态产生上述的sql语句?



看了上面的sql语句之后,相信大家已经基本明白该分页法的原理了。下面,我们将要设计一个动态生成sql语句的类fastpaging。该类有一个公有静态方法,它根据您给出的条件动态生成sql语句,作为方法的返回值。



// 产生根据指定字段排序并分页查询的 select 语句。

public static string paging(

int pagesize, //每页要显示的记录的数目。

int pageindex, //要显示的页的索引。

int recordcount, //数据表中的记录总数。

string tablename, //要查询的数据表。

string queryfields, //要查询的字段。

string primarykey, //主键字段。

bool ascending, //是否为升序排列。

string condition //查询的筛选条件。

) {

stringbuilder sb = new stringbuilder();

int pagecount = getpagecount(recordcount,pagesize); //分页的总数

int middleindex = getmidpageindex(pagecount); //中间页的索引

int firstindex = 0; //第一页的索引

int lastindex = pagecount - 1; //最后一页的索引



if (pageindex <= firstindex) {

// 代码略

} else if (pageindex > firstindex && pageindex <= middleindex) {

sb.append("select top ").append(pagesize).append(" ")

.append(queryfields).append(" from ").append(tablename)

.append(" where ").append(primarykey);

if (ascending)

sb.append(" > (").append(" select max(");

else

sb.append(" < (").append(" select min(");

sb.append(primarykey).append(") from ( select top ")

.append(pagesize*pageindex).append(" ").append(primarykey)

.append(" from ").append(tablename);

if (condition != string.empty)

sb.append(" where ").append(condition);

sb.append(" order by ").append(primarykey).append(" ")

.append(getsorttype(ascending)).append(" ) tablea )");

if (condition != string.empty)

sb.append(" and ").append(condition);

sb.append(" order by ").append(primarykey).append(" ")

.append(getsorttype(ascending));

}

else if (pageindex > middleindex && pageindex < lastindex) {

// 代码略

} else if (pageindex >= lastindex) {

// 代码略

}

return sb.tostring();

}




除了paging方法还有另外几个方法:



// 根据记录总数和分页大小计算分页数。

public static int getpagecount(int recordcount, int pagesize) {

return (int)math.ceiling((double)recordcount/pagesize);

}

// 计算中间页的页索引。

public static int getmidpageindex(int pagecount) {

return (int)math.ceiling((double)pagecount/2) - 1;

}

// 获取排序的方式("asc"表示升序,"desc"表示降序)

public static string getsorttype(bool ascending) {

return (ascending ? "asc" : "desc");

}

// 获取一个布尔值,该值指示排序的方式是否为升序。

public static bool isascending(string ordertype) {

return ((ordertype.toupper() == "desc") ? false : true);

}




让datagrid工作起来



有了上面的类,实现分页的工作就简单多了。首先,我们要将datagrid的allowpaging属性和allowcustompaging属性为true,除此之外,为了体现出升序和降序的功能,还需要将allowsorting属性也设置为true。然后在每次分页时,我们需要产生一个oledbdatareader对象或dataview对象绑定到datagrid,作为datagrid的数据源。这里需要用fastpaging类的paging方法根据条件产生一个sql语句,并赋给oledbcommand对象的commandtext属性:



cmd.commandtext = fastpaging.paging(

datagrid1.pagesize,

(int)viewstate["currentpageindex"],

datagrid1.virtualitemcount,

"items",

"itemid, productid, price",

"itemid",

fastpaging.isascending(ordertype),

""

);




在上面的程序段中,viewstate["currentpageindex"]的值在datagrid的page事件处理程序中被更新为e.newpageindex。为了方便处理viewstate的空值,最好把对viewstate["currentpageindex"]的存取操作和空值判断封装在一个属性里。datagrid1. virtualitemcount应该设置为数据库表中的记录总数。datagrid通过它和pagesize属性可以虚拟出datagrid的分页数。virtualitemcount的值是在page的load事件处理程序中被设置的,而该值的大小需要经过一次数据库访问才能得到。为了提高性能,可以只在第一次加载页面的时候设置该值。



总结



datagrid基于access的快速分页法到这里就介绍完了。当然,这种方法并不能“包治百病”,可能对于您的要实现的功能,还有其它更好的方法。这就需要大家在平时工作和学习中不断总结经验,在解决实际问题时尽可能找到最有效的方法。这也是本文的方法中所贯穿的思想。


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

文章页数:[1] 


放大字体显示 缩小字体显示 打印文章 推荐给朋友
热门文章
·jsp设置页面过期-JSP教程,Jsp/Servlet
·用SqlDataAdapter更新数据库的方法介绍-.NET教程,数据库应用
·用java关闭IE窗口-JSP教程,Java技巧及代码
·ADO.NET 2.0 Feature Matrix-ASP教程,ASP应用
·Jsp & Servlet 会话控制-JSP教程,Jsp/Servlet
·xmlhttp 乱码 的解决方法 (UTF8,GB2312 编码 解码)-ASP教程,XML相关
·使用C#编写Ice应用程序-.NET教程,C#语言
·用PHP实现WEB动态网页静态-PHP教程,PHP应用
·DataGrid基于Access的快速分页法-.NET教程,数据库应用
·HTML文档中小meta的大作用-ASP教程,XML相关
最新文章
·photoshop打造数码照片“像素块”特效_photoshop教程
·css中如何正确的使用id和class_css教程
·保证让新手轻松月挣500以上_网赚技巧
·记住10个关键词让你作一名成功的站长_站长心得
·对新人站长得一些善意得提醒_站长心得
·在windows vista中安装telnet客户端_windows vista
·怎样提高你的google adsense收入_站长心得
·googleadsense新手指南及常见问题整理_google推广
·高网站访问量的必胜之道:访google adwords经理(上)_google推广
·成功经验谈:运营blog的21个具体方法_网络编辑
相关主题
  • datagrid分页,增加首页、最后一页(源码) _asp.net技巧
  • datagridview 的分页处理_asp.net技巧
  • datagrid的多行提交_asp.net技巧
  • datagrid和datalist中commandbutton的问题_asp.net技巧
  • datagrid 的 全选/取消全选 控制(checkbox) _asp.net技巧
  • 西部数码虚拟主机

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