证明DataReader分页的可行性

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

 

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

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

 

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

 

 

 

 

 

 

 

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

下面是我的测试代码:

 

页面:简单的。

 

         < asp:GridView  ID ="GridView1"  runat ="server" >
        
</ asp:GridView >
       
    
< lcs:Pager  ID ="Pager1"  runat ="server"  onpagechanged ="Pager1_PageChanged"  AlwaysShow ="true"
        CurrentPageButtonPosition
="Center" >
    
</ 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); ;
10              }
11               else
12              {
13                  totalCount  =  LCS.Data.DbHelper. GetCount ( " Statistic " "" );
14                  GridView1.DataSource  =  LCS.Data.DbHelper. GetPager (
15                      Pager1.PageSize, Pager1.CurrentPageIndex,  " Statistic " " * " " StatisticID " false null );
16              }
17              Response.Write( " <hr/> "   +  (DateTime.Now.Ticks  -  beg) +   " <hr/> " );
18   
19              GridView1.DataBind();
20              Pager1.RecordCount  =  totalCount;
21          }

 

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

 

再看常规的:

       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          }

 

 

//我内部使用了一个格式化sql字符串参数的过程,所以这里有个中转。

 

 1     public   static  DbDataReader  ExecuteReader ( string  format,  params   object [] parameterValues)
 2          {
 3               if  (format  ==   null   ||  format.Length  ==   0 throw   new  ArgumentNullException( " commandText " );
 4               if  ((parameterValues  !=   null &&  (parameterValues.Length  >   0 ))
 5              {
 6                   // 当存在参数时,格式化参数
 7                  SQlParameterFormatter formatter  =   new  SQlParameterFormatter();
 8                  formatter.Provider  =  Provider;
 9                  formatter.Format(format, parameterValues);
10                   return  ExecuteReader(CommandType.Text, formatter.Sql, formatter.Parameters);
11              }
12               else // 无参数时直接掉用
13              {
14                   return  ExecuteReader(CommandType.Text, format, (DbParameter[]) null );
15              }
16         }

17   

 

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

         1 public string GetPagerSqlint pageSize, int pageIndex,

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

 

最后,给想直接看结果的一个连接:

http://jyt.dai8.net:89/test_cb.aspx

 

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

 

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

 

你可能感兴趣的:(reader)