证明DataReader分页的可行性

运维 数据库运维
记得那是07年的一个下午,我正在网上瞎逛,突然看到一段代码,也就是跟楼主上面的代码类似的,通过DataReader来分页的代码。当时我吓了一跳,这样的代码,是不是稍大些的系统就不能用了呢?

记得那是07年的一个下午,我正在网上瞎逛,突然看到一段代码,也就是跟楼主上面的代码类似的,通过DataReader来分页的代码。当时我吓了一跳,这样的代码,是不是稍大些的系统就不能用了呢?因为按我当时的理解,while (dr.Read()),若我的系统有几百万条的数据,那这个while也要转好久了,还要传数据,应该快不了的。可是后来经过我的测试,其实性能是很好的,至少不是我们想像中的那么慢的。

在那时候,我用我们系统里面的一个200多W的统计表进行了测试,只是简单的select * from table ,然后在程序里面 while 遍历,最后在GridView上面绑定了一下,效果很好。我记忆深刻,那会白天,在公司里面,前面几页运行良好,后面的页码,当然也包括最后一页,我都不敢去点,怕影响系统性能。等到了晚上回家,我半夜试了一下,居然跟前面几页差距不大,我那时候只是为了测试一下是否可行,也没有使用记时器,但是应该也是在5秒以内就返回了。前面的话,应该也是3,4秒的样子。太让我意外了,同时也太惊喜了。

不过因为系统框架里面都是使用的存储过程,也运行良好,也就一直没有去改过。也就是说,这套分页解决方案,在真正的大数据量下面,我也没有实际在项目中应用过,不过小项目倒是常用。

对于一般的系统来说,这个通用的分页解决方案就够用了。对于大一点的,可以通过其它手段,如分表或其它什么的,也能满足一般的应用。

想想发到首页,应该出点代码,就又花了些时间补充了一下。

下面是我的测试代码:

页面:简单的。

  1.     <asp:GridView ID="GridView1" runat="server"> 
  2.     </asp:GridView> 
  3.      
  4. <lcs:Pager ID="Pager1" runat="server" onpagechanged="Pager1_PageChanged" AlwaysShow="true" 
  5.     CurrentPageButtonPosition="Center"> 
  6. </lcs:Pager>  

后台代码:也是简单的。

  1. private void BindRpt()  
  2. {  
  3.    int totalCount;  
  4.    double beg = DateTime.Now.Ticks;  
  5.    if (isDatareader)  
  6.    {  
  7.       GridView1.DataSource = LCS.Data.DbHelper.GetPager(  
  8.          Pager1.PageSize, Pager1.CurrentPageIndex, "Statistic", "*", "StatisticID", false, out totalCount, null, null); ;  
  9.    }  
  10.    else  
  11.    {  
  12.       totalCount = LCS.Data.DbHelper.GetCount("Statistic", "");  
  13.       GridView1.DataSource = LCS.Data.DbHelper.GetPager(  
  14.          Pager1.PageSize, Pager1.CurrentPageIndex, "Statistic", "*", "StatisticID", false, null);  
  15.    }  
  16.    Response.Write("<hr/>" + (DateTime.Now.Ticks - beg)+ "<hr/>");  
  17.     
  18.    GridView1.DataBind();  
  19.    Pager1.RecordCount = totalCount;  
  20. }  

最后再附上我的DbHelper里面的方法实现:

先看使用datareader的

  1. public static DataTable GetPager(int pageSize, int pageIndex,  
  2.    string tblName, string fldName, string fldSort, bool isDesc,  
  3.    out int totalCount, string condition, params object[] parmsValues  
  4.    )  
  5. {  
  6.    //select * from talble where 11=1 order by fld desc  
  7.    //是标准的sql,不需要单独区分  
  8.    string sql = "select " + fldName + " from " + tblName.ToString()  
  9.       + ((string.IsNullOrEmpty(condition)) ? string.Empty : (" where 11=1 " + condition))  
  10.       + " order by " + fldSort.ToString() + (isDesc ? " DESC" : " ASC");  
  11.    using (DbDataReader reader = ExecuteReader(sql, parmsValues))  
  12.    {  
  13.       DataTable dt = new DataTable();  
  14.       int fieldCount = reader.FieldCount;  
  15.       for (int i = 0; i < fieldCount; i++)  
  16.       {  
  17.          DataColumn col = new DataColumn();  
  18.          col.ColumnName = reader.GetName(i);  
  19.          col.DataType = reader.GetFieldType(i);  
  20.          dt.Columns.Add(col);  
  21.       }  
  22.       totalCount = 0;  
  23.       int first = (pageIndex - 1) * pageSize + 1;  
  24.       int last = pageIndex * pageSize;  
  25.       while (reader.Read())  
  26.       {  
  27.          totalCount++;  
  28.          if (totalCount >= first && last >= totalCount)  
  29.          {  
  30.             DataRow r = dt.NewRow();  
  31.             for (int i = 0; i < fieldCount; i++)  
  32.             {  
  33.                r[i] = reader[i];  
  34.             }  
  35.             dt.Rows.Add(r);  
  36.          }  
  37.       }  
  38.       return dt;  
  39.    }  

再看常规的:

  1. public static DbDataReader GetPager(int pageSize, int pageIndex,  
  2. string tblName, string fldName, string fldSort, bool isDesc, string condition)  
  3. {  
  4.    return ExecuteReader(Provider.GetPagerSql(pageSize, pageIndex, tblName, fldName, fldSort, isDesc, condition));  
  5. }   
  6.  
  7. //我内部使用了一个格式化sql字符串参数的过程,所以这里有个中转。  
  8.  
  9. public static DbDataReader ExecuteReader(string format, params object[] parameterValues)  
  10. {  
  11.    if (format == null || format.Length == 0) throw new ArgumentNullException("commandText");  
  12.    if ((parameterValues != null) && (parameterValues.Length > 0))  
  13.    {  
  14.       //当存在参数时,格式化参数  
  15.       SQlParameterFormatter formatter = new SQlParameterFormatter();  
  16.       formatter.Provider = Provider;  
  17.       formatter.Format(format, parameterValues);  
  18.       return ExecuteReader(CommandType.Text, formatter.Sql, formatter.Parameters);  
  19.    }  
  20.    else//无参数时直接掉用  
  21.    {  
  22.       return ExecuteReader(CommandType.Text, format, (DbParameter[])null);  
  23.    }  
  24. }    

//最后再看一下生成分页sql字符串的方法

  1. public string GetPagerSql( int pageSize, int pageIndex,  
  2. string tblName,string fldName,string fldSort, bool isDesc,string condition)  
  3. {  
  4.    string strSort = isDesc ? " DESC" : " ASC";  
  5.    if (pageIndex == 1)  
  6.    {  
  7.       return "select top " + pageSize.ToString() + " " + fldName + " from " + tblName.ToString()  
  8.       + ((string.IsNullOrEmpty(condition)) ? string.Empty : (" where " + condition))  
  9.       + " order by " + fldSort.ToString() + strSort;  
  10.    }  
  11.    else  
  12.    {  
  13.       System.Text.StringBuilder strSql = new System.Text.StringBuilder();  
  14.       strSql.AppendFormat("select top {0} {1} from {2} ", pageSize,fldName, tblName);  
  15.       strSql.AppendFormat(" where {1} not in (select top {0} {1} from {2} ", pageSize * (pageIndex - 1),  
  16.       (fldSort.Substring(fldSort.LastIndexOf(',') + 1, fldSort.Length - fldSort.LastIndexOf(',') - 1)), tblName);  
  17.       if (!string.IsNullOrEmpty(condition))  
  18.       {  
  19.          strSql.AppendFormat(" where {0} order by {1}{2}) and {0}", condition, fldSort, strSort);  
  20.       }  
  21.       else  
  22.       {  
  23.          strSql.AppendFormat(" order by {0}{1}) ", fldSort, strSort);  
  24.       }  
  25.       strSql.AppendFormat(" order by {0}{1}", fldSort, strSort);  
  26.       return strSql.ToString();  
  27.    }  

最后,给想直接看结果的一个连接:http://jyt.dai8.net:89/test_cb.aspx

可别把我的电脑给搞死啦。

经过我的测试,常规的还是比datareader的要来得快,若单是从数值上面看的话,差距还蛮大的,大的差10多倍,小的也要差3,4倍 ,不过对于实用性来说,也是够用啦。因为很多时候,用户是感觉不到的,特别是那些客户端的,或是企业内部使用的,基本上没有并发的项目。

原文链接:http://www.cnblogs.com/luchaoshuai/archive/2011/04/27/2029937.html

【编辑推荐】

  1. 详解数据库分页操作
  2. sql server存储过程分页总结
  3. 双TOP二分法生成分页SQL类
  4. 浅谈SQL Server2005的几种分页方法
  5. Access分页方案
责任编辑:艾婧 来源: 博客园
相关推荐

2012-04-12 17:41:02

2009-09-21 16:40:42

Hibernate可行

2011-06-24 11:35:01

内链

2009-12-25 14:26:40

无线接入技术集成

2011-12-13 20:36:26

Android

2009-02-17 15:59:55

2009-06-15 09:57:46

HibernateIBatis

2013-08-27 11:15:20

2012-10-26 13:48:54

2011-11-14 09:10:08

虚拟化

2020-09-16 09:19:49

数据中心

2012-04-09 09:39:59

虚拟化桌面虚拟化VDI终端

2022-03-11 08:31:50

API网关微服务

2011-08-17 13:07:19

无线局域网

2011-12-02 09:25:46

2019-10-21 17:17:48

Windows操作系统微软

2011-07-05 14:12:06

关键任务虚拟化服务器

2011-07-05 10:37:03

虚拟化VMware

2023-08-20 12:34:53

2020-09-28 07:00:00

单元测试编程语言
点赞
收藏

51CTO技术栈公众号