證明DataReader分頁(yè)的可行性
記得那是07年的一個(gè)下午,我正在網(wǎng)上瞎逛,突然看到一段代碼,也就是跟樓主上面的代碼類似的,通過(guò)DataReader來(lái)分頁(yè)的代碼。當(dāng)時(shí)我嚇了一跳,這樣的代碼,是不是稍大些的系統(tǒng)就不能用了呢?因?yàn)榘次耶?dāng)時(shí)的理解,while (dr.Read()),若我的系統(tǒng)有幾百萬(wàn)條的數(shù)據(jù),那這個(gè)while也要轉(zhuǎn)好久了,還要傳數(shù)據(jù),應(yīng)該快不了的??墒呛髞?lái)經(jīng)過(guò)我的測(cè)試,其實(shí)性能是很好的,至少不是我們想像中的那么慢的。
在那時(shí)候,我用我們系統(tǒng)里面的一個(gè)200多W的統(tǒng)計(jì)表進(jìn)行了測(cè)試,只是簡(jiǎn)單的select * from table ,然后在程序里面 while 遍歷,最后在GridView上面綁定了一下,效果很好。我記憶深刻,那會(huì)白天,在公司里面,前面幾頁(yè)運(yùn)行良好,后面的頁(yè)碼,當(dāng)然也包括最后一頁(yè),我都不敢去點(diǎn),怕影響系統(tǒng)性能。等到了晚上回家,我半夜試了一下,居然跟前面幾頁(yè)差距不大,我那時(shí)候只是為了測(cè)試一下是否可行,也沒(méi)有使用記時(shí)器,但是應(yīng)該也是在5秒以內(nèi)就返回了。前面的話,應(yīng)該也是3,4秒的樣子。太讓我意外了,同時(shí)也太驚喜了。
不過(guò)因?yàn)橄到y(tǒng)框架里面都是使用的存儲(chǔ)過(guò)程,也運(yùn)行良好,也就一直沒(méi)有去改過(guò)。也就是說(shuō),這套分頁(yè)解決方案,在真正的大數(shù)據(jù)量下面,我也沒(méi)有實(shí)際在項(xiàng)目中應(yīng)用過(guò),不過(guò)小項(xiàng)目倒是常用。
對(duì)于一般的系統(tǒng)來(lái)說(shuō),這個(gè)通用的分頁(yè)解決方案就夠用了。對(duì)于大一點(diǎn)的,可以通過(guò)其它手段,如分表或其它什么的,也能滿足一般的應(yīng)用。
想想發(fā)到首頁(yè),應(yīng)該出點(diǎn)代碼,就又花了些時(shí)間補(bǔ)充了一下。
下面是我的測(cè)試代碼:
頁(yè)面:簡(jiǎn)單的。
- <asp:GridView ID="GridView1" runat="server">
 - </asp:GridView>
 - <lcs:Pager ID="Pager1" runat="server" onpagechanged="Pager1_PageChanged" AlwaysShow="true"
 - CurrentPageButtonPosition="Center">
 - </lcs:Pager>
 
后臺(tái)代碼:也是簡(jiǎn)單的。
- private void BindRpt()
 - {
 - int totalCount;
 - double beg = DateTime.Now.Ticks;
 - if (isDatareader)
 - {
 - GridView1.DataSource = LCS.Data.DbHelper.GetPager(
 - Pager1.PageSize, Pager1.CurrentPageIndex, "Statistic", "*", "StatisticID", false, out totalCount, 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里面的方法實(shí)現(xiàn):
先看使用datareader的
- public static DataTable GetPager(int pageSize, int pageIndex,
 - string tblName, string fldName, string fldSort, bool isDesc,
 - out int totalCount, string condition, params object[] parmsValues
 - )
 - {
 - //select * from talble where 11=1 order by fld desc
 - //是標(biāo)準(zhǔn)的sql,不需要單獨(dú)區(qū)分
 - string sql = "select " + fldName + " from " + tblName.ToString()
 - + ((string.IsNullOrEmpty(condition)) ? string.Empty : (" where 11=1 " + condition))
 - + " order by " + fldSort.ToString() + (isDesc ? " DESC" : " ASC");
 - using (DbDataReader reader = ExecuteReader(sql, parmsValues))
 - {
 - DataTable dt = new DataTable();
 - int fieldCount = reader.FieldCount;
 - for (int i = 0; i < fieldCount; i++)
 - {
 - DataColumn col = new DataColumn();
 - col.ColumnName = reader.GetName(i);
 - col.DataType = reader.GetFieldType(i);
 - dt.Columns.Add(col);
 - }
 - totalCount = 0;
 - int first = (pageIndex - 1) * pageSize + 1;
 - int last = pageIndex * pageSize;
 - while (reader.Read())
 - {
 - totalCount++;
 - if (totalCount >= first && last >= totalCount)
 - {
 - DataRow r = dt.NewRow();
 - for (int i = 0; i < fieldCount; i++)
 - {
 - r[i] = reader[i];
 - }
 - dt.Rows.Add(r);
 - }
 - }
 - return dt;
 - }
 - }
 
再看常規(guī)的:
- public static DbDataReader GetPager(int pageSize, int pageIndex,
 - string tblName, string fldName, string fldSort, bool isDesc, string condition)
 - {
 - return ExecuteReader(Provider.GetPagerSql(pageSize, pageIndex, tblName, fldName, fldSort, isDesc, condition));
 - }
 - //我內(nèi)部使用了一個(gè)格式化sql字符串參數(shù)的過(guò)程,所以這里有個(gè)中轉(zhuǎn)。
 - public static DbDataReader ExecuteReader(string format, params object[] parameterValues)
 - {
 - if (format == null || format.Length == 0) throw new ArgumentNullException("commandText");
 - if ((parameterValues != null) && (parameterValues.Length > 0))
 - {
 - //當(dāng)存在參數(shù)時(shí),格式化參數(shù)
 - SQlParameterFormatter formatter = new SQlParameterFormatter();
 - formatter.Provider = Provider;
 - formatter.Format(format, parameterValues);
 - return ExecuteReader(CommandType.Text, formatter.Sql, formatter.Parameters);
 - }
 - else//無(wú)參數(shù)時(shí)直接掉用
 - {
 - return ExecuteReader(CommandType.Text, format, (DbParameter[])null);
 - }
 - }
 
//最后再看一下生成分頁(yè)sql字符串的方法
- public string GetPagerSql( int pageSize, int pageIndex,
 - string tblName,string fldName,string fldSort, bool isDesc,string condition)
 - {
 - string strSort = isDesc ? " DESC" : " ASC";
 - if (pageIndex == 1)
 - {
 - return "select top " + pageSize.ToString() + " " + fldName + " from " + tblName.ToString()
 - + ((string.IsNullOrEmpty(condition)) ? string.Empty : (" where " + condition))
 - + " order by " + fldSort.ToString() + strSort;
 - }
 - else
 - {
 - System.Text.StringBuilder strSql = new System.Text.StringBuilder();
 - strSql.AppendFormat("select top {0} {1} from {2} ", pageSize,fldName, tblName);
 - strSql.AppendFormat(" where {1} not in (select top {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} order by {1}{2}) and {0}", condition, fldSort, strSort);
 - }
 - else
 - {
 - strSql.AppendFormat(" order by {0}{1}) ", fldSort, strSort);
 - }
 - strSql.AppendFormat(" order by {0}{1}", fldSort, strSort);
 - return strSql.ToString();
 - }
 - }
 
最后,給想直接看結(jié)果的一個(gè)連接:http://jyt.dai8.net:89/test_cb.aspx
可別把我的電腦給搞死啦。
經(jīng)過(guò)我的測(cè)試,常規(guī)的還是比datareader的要來(lái)得快,若單是從數(shù)值上面看的話,差距還蠻大的,大的差10多倍,小的也要差3,4倍 ,不過(guò)對(duì)于實(shí)用性來(lái)說(shuō),也是夠用啦。因?yàn)楹芏鄷r(shí)候,用戶是感覺(jué)不到的,特別是那些客戶端的,或是企業(yè)內(nèi)部使用的,基本上沒(méi)有并發(fā)的項(xiàng)目。
原文鏈接:http://www.cnblogs.com/luchaoshuai/archive/2011/04/27/2029937.html
【編輯推薦】















 
 
 



 
 
 
 