程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 數據庫知識 >> SqlServer數據庫 >> 關於SqlServer >> 證明DataReader分頁的可行性

證明DataReader分頁的可行性

編輯:關於SqlServer
 

記得那是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. <lcs:Pager ID="Pager1" runat="server" onpagechanged="Pager1_PageChanged" AlwaysShow="true"
  4. CurrentPageButtonPosition="Center">
  5. </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",
  9. 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. 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. }
  40. }

再看常規的:

  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,
  5. fldSort, isDesc, condition));
  6. }
  7. //我內部使用了一個格式化sql字符串參數的過程,所以這裡有個中轉。
  8. public static DbDataReader ExecuteReader(string format, params object[] parameterValues)
  9. {
  10. if (format == null || format.Length == 0) throw new ArgumentNullException("commandText");
  11. if ((parameterValues != null) && (parameterValues.Length > 0))
  12. {
  13. //當存在參數時,格式化參數
  14. SQlParameterFormatter formatter = new SQlParameterFormatter();
  15. formatter.Provider = Provider;
  16. formatter.Format(format, parameterValues);
  17. return ExecuteReader(CommandType.Text, formatter.Sql, formatter.Parameters);
  18. }
  19. else//無參數時直接掉用
  20. {
  21. return ExecuteReader(CommandType.Text, format, (DbParameter[])null);
  22. }
  23. }

//最後再看一下生成分頁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} ",
  16. pageSize * (pageIndex - 1),
  17. (fldSort.Substring(fldSort.LastIndexOf(',') + 1,
  18. fldSort.Length - fldSort.LastIndexOf(',') - 1)),
  19. tblName);
  20. if (!string.IsNullOrEmpty(condition))
  21. {
  22. strSql.AppendFormat(" where {0} order by {1}{2}) and {0}", condition, fldSort, strSort);
  23. }
  24. else
  25. {
  26. strSql.AppendFormat(" order by {0}{1}) ", fldSort, strSort);
  27. }
  28. strSql.AppendFormat(" order by {0}{1}", fldSort, strSort);
  29. return strSql.ToString();
  30. }
  31. }

最後,給想直接看結果的一個連接:http://jyt.dai8.net:89/test_cb.aspx

可別把我的電腦給搞死啦。

經過我的測試,常規的還是比datareader的要來得快,若單是從數值上面看的話,差距還蠻大的,大的差10多倍,小的也要差3,4倍 ,不過對於實用性來說,也是夠用啦。因為很多時候,用戶是感覺不到的,特別是那些客戶端的,或是企業內部使用的,基本上沒有並發的項目。

 
  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved