`

DataGrid基于Access的快速分页法

阅读更多
 

DataGrid基于Access的快速分页法<!----><o:p></o:p>

<o:p> </o:p>

撰文/ 黎波<o:p></o:p>

<o:p> </o:p>

DataGrid是一个功能非常强大的ASP.NET Web服务器端控件,它除了能够方便地按各种方式格式化显示表格中的数据,还可以对表格中的数据进行动态的排序、编辑和分页。使Web开发人员从繁琐的代码中解放。实现DataGrid的分页功能一直是很多初学ASP.NET的人感到棘手的问题,特别是自定义分页功能,实现方法多种多样,非常灵活。本文将向大家介绍一种DataGird控件在Access数据库下的快速分页法,帮助初学者掌握DataGrid的分页技术。<o:p></o:p>

<o:p> </o:p>

目前的分页方法<o:p></o:p>

<o:p> </o:p>

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

<o:p> </o:p>

还有一种方法是使用自定义分页功能,先将DataGridAllowCustomPaging属性设置为True,再利用DataAdapterFill方法将数据的筛选工作提前到填充DataSet时,而不是让DataGrid帮你筛选:<o:p></o:p>

<o:p> </o:p>

public int Fill (<o:p></o:p>

         DataSet dataSet,              //要填充的 DataSet<o:p></o:p>

         int startRecord,          //从其开始的从零开始的记录号。<o:p></o:p>

         int maxRecords,          //要检索的最大记录数。<o:p></o:p>

         string srcTable            //用于表映射的源表的名称。<o:p></o:p>

);<o:p></o:p>

<o:p> </o:p>

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

<o:p> </o:p>

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

<o:p> </o:p>

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

<o:p> </o:p>

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

<o:p> </o:p>

为了方便接下来的讨论,我们先约定如下:<o:p></o:p>

<o:p> </o:p>

变量<o:p></o:p>

说明<o:p></o:p>

变量<o:p></o:p>

说明<o:p></o:p>

@PageSize<o:p></o:p>

每页显示的记录总数<o:p></o:p>

@MiddleIndex<o:p></o:p>

中间页的索引<o:p></o:p>

@PageCount<o:p></o:p>

分页总数<o:p></o:p>

@LastIndex<o:p></o:p>

最后一页的索引<o:p></o:p>

@RecordCount<o:p></o:p>

数据表的记录总数<o:p></o:p>

@TableName<o:p></o:p>

数据库表名称<o:p></o:p>

@PageIndex<o:p></o:p>

当前页的索引<o:p></o:p>

@PrimaryKey<o:p></o:p>

主键字段名称<o:p></o:p>

@FirstIndex<o:p></o:p>

第一页的索引<o:p></o:p>

@QueryFields<o:p></o:p>

要查询的字段集<o:p></o:p>

<o:p> </o:p>

变量

定义

@PageCount

(int)Math.Ceiling((double)@RecordCount / @PageSize)

@FirstIndex

0

@LastIndex

@PageCount – 1

@MiddleIndex

(int)Math.Ceiling((double)@PageCount / 2) – 1

<o:p> </o:p>

先让我们看看效率最差的SQL语句:<o:p></o:p>

<o:p> </o:p>

SELECT TOP @PageSize * FROM @TableName <o:p></o:p>

WHERE @PrimaryKey NOT IN ( <o:p></o:p>

  SELECT TOP @PageSize*@PageIndex @PrimaryKey FROM @TableName <o:p></o:p>

  ORDER BY @PrimaryKey ASC <o:p></o:p>

) ORDER BY @PrimaryKey ASC <o:p></o:p>

<o:p> </o:p>

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

<o:p> </o:p>

另一种是使用了两个TOP和三个ORDER BYSQL语句,如下所示:<o:p></o:p>

<o:p> </o:p>

SELECT * FROM ( <o:p></o:p>

  SELECT TOP @PageSize * FROM ( <o:p></o:p>

SELECT TOP @PageSize*(@PageIndex+1) * FROM @TableName <o:p></o:p>

ORDER BY @PrimaryKey ASC<o:p></o:p>

) TableA ORDER BY @PrimaryKey DESC <o:p></o:p>

) TableB ORDER BY @PrimaryKey ASC <o:p></o:p>

<o:p> </o:p>

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

<o:p> </o:p>

有关主键和索引的概念<o:p></o:p>

<o:p> </o:p>

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

<o:p> </o:p>

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

<o:p> </o:p>

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

<o:p> </o:p>

快速分页法的原理<o:p></o:p>

<o:p> </o:p>

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

<o:p> </o:p>

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

1@PageIndex <= @FirstIndex <o:p></o:p>

2@FirstIndex < @PageIndex <= @MiddleIndex <o:p></o:p>

3@MiddleIndex < @PageIndex < @LastIndex <o:p></o:p>

4@PageIndex >= @LastIndex <o:p></o:p>

<o:p> </o:p>

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

<o:p> </o:p>

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

<o:p> </o:p>

PageIndex<o:p></o:p>

ItemId<o:p></o:p>

ProductId<o:p></o:p>

Price<o:p></o:p>

0<o:p></o:p>

001<o:p></o:p>

0011<o:p></o:p>

$12<o:p></o:p>

002<o:p></o:p>

分享到:
评论

相关推荐

    ASPNet中DataGrid基于Access的快速分页法.docx

    ASPNet中DataGrid基于Access的快速分页法.docx

    VC下利用CADO Class(ado2.cpp和ado2.h)和DataGrid分页显示数据库access内容

    本文主要初步介绍在VC6环境下利用CADO class,datagrid分页显示数据。 1、用VC操作数据库是非常麻烦的,网上关于VC下利用ADO和datagrid操作数据库的教程也很多,但无非是相互抄袭。 2、ADO使用起来麻烦,然而一个...

    VB6 设计带记忆的DataGrid数据录入窗口.rar

    VB6 设计带记忆的数据录入窗口,这种记忆实际上是将DataGrid临时输入的数据存入到数据库中了,是一个数据库应用范例,本例子中的数据库采用的Access。在本例中,用户临时对任意DataGrid行列操作时输入的内容,临时...

    .NET 通用分页控件

    分页是Web应用程序中最常用到的功能之一,在ASP.NET中,虽然自带了一个可以分页的DataGrid(asp.net 1.1)和GridView(asp.net 2.0)控件,但其分页功能并不尽如人意,如可定制性差、无法通过Url实现分页功能等,...

    九头鸭.net分页控件 v1.1.rar

    DataPage除提供默认的类似于DataGrid和GridView的PostBack分页方式外,还支持通过Url进行分页,象大多数asp程序中分页一样, Url分页方式允许用户通过在浏览器地址栏中输入相应的地址即可直接进入指定页面,也可以使...

    九头鸭分页控件 Url分页方式

    DataPage除提供默认的类似于DataGrid和GridView的PostBack分页方式外,还支持通过Url进行分页,象大多数asp程序中分页一样, Url分页方式允许用户通过在浏览器地址栏中输入相应的地址即可直接进入指定页面,也可以使...

    Asp.net分页控件AspNetPager7.2

    分页是Web应用程序中最常用到的功能之一,在ASP.NET中,虽然自带了一个可以分页的DataGrid(asp.net 1.1)和GridView(asp.net 2.0)控件,但其分页功能并不尽如人意,如可定制性差、无法通过Url实现分页功能等,...

    分页控件AspNetPager7.2c#源码

    分页是Web应用程序中最常用到的功能之一,在ASP.NET中,虽然自带了一个可以分页的DataGrid(asp.net 1.1)和GridView(asp.net 2.0)控件,但其分页功能并不尽如人意,如可定制性差、无法通过Url实现分页功能等,...

    AspNetPager7.2分页控件及Demo源码

    因为AspNetPager控件和数据是独立的,因此要分页的数据可以来自任何数据源,如SQL Server、Oracle、Access、mysql、DB2等数据库以及XML文件、内存数据或缓存中的数据、文件系统等等。 AspNetPager 7.2 版发布 新增...

    九头鸭分页控件源码

    DataPage除提供默认的类似于DataGrid和GridView的PostBack分页方式外,还支持通过Url进行分页,象大多数asp程序中分页一样, Url分页方式允许用户通过在浏览器地址栏中输入相应的地址即可直接进入指定页面,也可以使...

    AspNetPagerv7.4.1分页控件及Demo源码2012919

    因为AspNetPager控件和数据是独立的,因此要分页的数据可以来自任何数据源,如SQL Server、Oracle、Access、mysql、DB2等数据库以及XML文件、内存数据或缓存中的数据、文件系统等等。 AspNetPager的主要功能有: 1...

    九头鸭.net分页控件DataPage.rar

    DataPage除提供默认的类似于DataGrid和GridView的PostBack分页方式外,还支持通过Url进行分页,象大多数asp程序中分页一样, Url分页方式允许用户通过在浏览器地址栏中输入相应的地址即可直接进入指定页面,也可以使...

    AspNetPager 分页控件

    分页是Web应用程序中最常用到的功能之一,在ASP.NET中,虽然自带了一个可以分页的DataGrid(asp.net 1.1)和GridView(asp.net 2.0)控件,但其分页功能并不尽如人意,如可定制性差、无法通过Url实现分页功能等,...

    AspNetPager分页控件

    分页是Web应用程序中最常用到的功能之一,在ASP.NET中,虽然自带了一个可以分页的DataGrid(asp.net 1.1)和GridView(asp.net 2.0)控件,但其分页功能并不尽如人意,如可定制性差、无法通过Url实现分页功能等,...

    asp.net Repeater分页实例(PageDataSource的使用)

    Asp.net提供了三个功能强大的列表控件:DataGrid、DataList和Repeater控件,但其中只有DataGrid控件提供分页功能。相对DataGrid,DataList和Repeater控件具有更高的样式自定义性,所以很多时候我们喜欢使用DataList...

    AspNetPager控件及Demo源码.7z

    分页是Web应用程序中最常用到的功能之一,在ASP.NET中,虽然自带了一个可以分页的DataGrid(Asp.Net 1.1)和GridView(Asp.Net 2.0)控件,但其分页功能并不尽如人意,如可定制性差、无法通过Url实现分页功能等,...

    AspNetPager741Src最新源码

    分页是Web应用程序中最常用到的功能之一,在ASP.NET中,虽然自带了一个可以分页的DataGrid(asp.net 1.1)和GridView(asp.net 2.0)控件,但其分页功能并不尽如人意,如可定制性差、无法通过Url实现分页功能等, ...

Global site tag (gtag.js) - Google Analytics