首页 运维 正文
证明DataReader分页的可行性

 2022-10-23    316  

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

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

证明DataReader分页的可行性

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

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

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

下面是我的测试代码:

页面:简单的。

<asp:GridViewID="GridView1"runat="server">
</asp:GridView>
 
<lcs:PagerID="Pager1"runat="server"onpagechanged="Pager1_PageChanged"AlwaysShow="true"
CurrentPageButtonPosition="Center">
</lcs:Pager>

后台代码:也是简单的。

privatevoidBindRpt() 
{ 
inttotalCount; 
doublebeg=DateTime.Now.Ticks; 
if(isDatareader) 
{ 
GridView1.DataSource=LCS.Data.DbHelper.GetPager( 
Pager1.PageSize,Pager1.CurrentPageIndex,"Statistic","*","StatisticID",false,outtotalCount,null,null);; 
} 
else 
{ 
totalCount=LCS.Data.DbHelper.GetCount("Statistic",""); 
GridView1.DataSource=LCS.Data.DbHelper.GetPager( 
Pager1.PageSize,Pager1.CurrentPageIndex,"Statistic","*","StatisticID",false,null); 
} 
Response.Write("<hr/>"+(DateTime.Now.Ticks-beg)+"<hr/>"); 
 
GridView1.DataBind(); 
Pager1.RecordCount=totalCount; 
}

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

先看使用datareader的

publicstaticDataTableGetPager(intpageSize,intpageIndex, 
stringtblName,stringfldName,stringfldSort,boolisDesc, 
outinttotalCount,stringcondition,paramsobject[]parmsValues 
) 
{ 
//select*fromtalblewhere11=1orderbyflddesc 
//是标准的sql,不需要单独区分 
stringsql="select"+fldName+"from"+tblName.ToString() 
+((string.IsNullOrEmpty(condition))?string.Empty:("where11=1"+condition)) 
+"orderby"+fldSort.ToString()+(isDesc?"DESC":"ASC"); 
using(DbDataReaderreader=ExecuteReader(sql,parmsValues)) 
{ 
DataTabledt=newDataTable(); 
intfieldCount=reader.FieldCount; 
for(inti=0;i<fieldCount;i++) 
{ 
DataColumncol=newDataColumn(); 
col.ColumnName=reader.GetName(i); 
col.DataType=reader.GetFieldType(i); 
dt.Columns.Add(col); 
} 
totalCount=0; 
intfirst=(pageIndex-1)*pageSize+1; 
intlast=pageIndex*pageSize; 
while(reader.Read()) 
{ 
totalCount++; 
if(totalCount>=first&&last>=totalCount) 
{ 
DataRowr=dt.NewRow(); 
for(inti=0;i<fieldCount;i++) 
{ 
r[i]=reader[i]; 
} 
dt.Rows.Add(r); 
} 
} 
returndt; 
} 
}

再看常规的:

publicstaticDbDataReaderGetPager(intpageSize,intpageIndex, 
stringtblName,stringfldName,stringfldSort,boolisDesc,stringcondition) 
{ 
returnExecuteReader(Provider.GetPagerSql(pageSize,pageIndex,tblName,fldName,fldSort,isDesc,condition)); 
} 

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

publicstaticDbDataReaderExecuteReader(stringformat,paramsobject[]parameterValues) 
{ 
if(format==null||format.Length==0)thrownewArgumentNullException("commandText"); 
if((parameterValues!=null)&&(parameterValues.Length>0)) 
{ 
//当存在参数时,格式化参数 
SQlParameterFormatterformatter=newSQlParameterFormatter(); 
formatter.Provider=Provider; 
formatter.Format(format,parameterValues); 
returnExecuteReader(CommandType.Text,formatter.Sql,formatter.Parameters); 
} 
else//无参数时直接掉用 
{ 
returnExecuteReader(CommandType.Text,format,(DbParameter[])null); 
} 
}

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

publicstringGetPagerSql(intpageSize,intpageIndex, 
stringtblName,stringfldName,stringfldSort,boolisDesc,stringcondition) 
{ 
stringstrSort=isDesc?"DESC":"ASC"; 
if(pageIndex==1) 
{ 
return"selecttop"+pageSize.ToString()+""+fldName+"from"+tblName.ToString() 
+((string.IsNullOrEmpty(condition))?string.Empty:("where"+condition)) 
+"orderby"+fldSort.ToString()+strSort; 
} 
else 
{ 
System.Text.StringBuilderstrSql=newSystem.Text.StringBuilder(); 
strSql.AppendFormat("selecttop{0}{1}from{2}",pageSize,fldName,tblName); 
strSql.AppendFormat("where{1}notin(selecttop{0}{1}from{2}",pageSize*(pageIndex-1), 
(fldSort.Substring(fldSort.LastIndexOf(',')+1,fldSort.Length-fldSort.LastIndexOf(',')-1)),tblName); 
if(!string.IsNullOrEmpty(condition)) 
{ 
strSql.AppendFormat("where{0}orderby{1}{2})and{0}",condition,fldSort,strSort); 
} 
else 
{ 
strSql.AppendFormat("orderby{0}{1})",fldSort,strSort); 
} 
strSql.AppendFormat("orderby{0}{1}",fldSort,strSort); 
returnstrSql.ToString(); 
} 
}

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

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

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

原文链接:https://77isp.com/post/7040.html

=========================================

https://77isp.com/ 为 “云服务器技术网” 唯一官方服务平台,请勿相信其他任何渠道。