分頁的筆記

  • 2799
  • 0
  • 2010-04-22

摘要:分頁的筆記

4-8-4、GridView 的效能

OK,GridView 控件功能很強大,但是如果你仔細思考下 GridView 控件的分頁是如何做的,會發現她的做法其實隱含著一個很大的效能問題,GridView 控件在分頁功能啟動的情況下,會建立一個 PageDataSource 物件,由這個物件負責向 DataSource 索取資料,於索取資料時一併傳入 DataSourceSelectArgument 物件,此物件中便包含了起始的列及需要的列數,看起來似乎沒啥問題嗎?其實不然,當 DataSource 控件不支援分頁時,PageDataSource  物件只能以該 DataSource 所傳回的資料來做分頁,簡略的說!

SqlDataSource 控件是不支援分頁的,這時 PageDataSource 會要求 SqlDataSource 控件傳回資料,而 SqlDataSource 控件就用 SelectQuery 中的 SQL 指令向資料庫要求資料,結果便是,當該 SQL 指令選取 100000 筆資料時,SqlDataSource 所傳回給 PageDataSource 的資料也是 100000 筆!!這意味著,GridView 每次做資料繫結顯示時,是用 100000 筆資料在分頁,不管顯示的是幾筆,存在於記憶體中的都是 100000 筆!如果同時有 10 個人、100 個人在使用此網頁,可想而知 Server 的負擔有多重了,即使有 Cache 加持,一樣會有 100000 筆資料在記憶體中!以往在 ASP.NET 1.1 時,可以運用 DataGrid 控件的 CustomPaging 功能來解決此問題,但 GridView 控件並未提供這個功能,我們該怎麼處理這個問題呢?在提出解決方案前,我們先談談 GridView 控件為何將這麼有用的功能移除了?答案很簡單,這個功能已經被移往 DataSource 控件了,這是因為 DataSource 控件所需服務的不只是 GridView,FormView、DetailsView 都需要她,而且她們都支援分頁,如果將 CustomPaging 直接做在這些控件上,除了控件必須有著重複的程式碼外,設計師於撰寫分頁程式時,也需針對不同的控件來處理,將這些移往 DataSource 控件後,便只會有一份程式碼。說來好聽,那明擺著 SqlDataSource 控件就不支援手動分頁了,那該如何解決這個問題了,答案是 ObjectDataSource,這是一個支援分頁的 DataSource 控件,只要設定幾個屬性及對資料提供者做適當的修改後,便可以達到手動分頁的效果了。請建立一個 WebiSte 專案,添加一個 DataSet 連結到 Northwind 的 Customers 資料表,接著新增一個 Class,檔名為 NorthwindCustomersTableAdapter.cs,鍵入下面的程式碼。


using System;
using System.ComponentModel;
using System.Data;
using System.Data.SqlClient;
using System.Configuration;
using System.Web;
using System.Web.Security;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Web.UI.WebControls.WebParts;
using System.Web.UI.HtmlControls;

namespace NorthwindTableAdapters
{
    public partial class CustomersTableAdapter
    {
        [System.ComponentModel.DataObjectMethodAttribute(
System.ComponentModel.DataObjectMethodType.Select, true)]
        public virtual Northwind.CustomersDataTable GetData(int startRowIndex, int maximumRows)
        {
            this.Adapter.SelectCommand =
 new System.Data.SqlClient.SqlCommand("SELECT {COLUMNS} FROM " +
 "(SELECT {COLUMNS},ROW_NUMBER() OVER(ORDER BY {SORT}) As RowNumber FROM {TABLE} {WHERE}) {TABLE} " + 
 "WHERE RowNumber > {START} AND RowNumber < {FETCH_SIZE}",Connection);
            this.Adapter.SelectCommand.CommandText = this.Adapter.SelectCommand.CommandText.Replace("{COLUMNS}", "*");
            this.Adapter.SelectCommand.CommandText = this.Adapter.SelectCommand.CommandText.Replace("{TABLE}", "Customers");
            this.Adapter.SelectCommand.CommandText = this.Adapter.SelectCommand.CommandText.Replace("{SORT}", "CustomerID");
            this.Adapter.SelectCommand.CommandText = this.Adapter.SelectCommand.CommandText.Replace("{WHERE}", "");
            this.Adapter.SelectCommand.CommandText = this.Adapter.SelectCommand.CommandText.Replace("{START}", startRowIndex.ToString());
            this.Adapter.SelectCommand.CommandText = this.Adapter.SelectCommand.CommandText.Replace("{FETCH_SIZE}", (startRowIndex+maximumRows).ToString());
            Northwind.CustomersDataTable dataTable = new Northwind.CustomersDataTable();
            this.Adapter.Fill(dataTable);
            return dataTable;
        }

        public virtual int GetCount(int startRowIndex, int maximumRows)
        {
            SqlCommand cmd = new System.Data.SqlClient.SqlCommand("SELECT COUNT(*) AS TOTAL_COUNT FROM Customers", Connection);            
            Connection.Open();
            try
            {
                return (int)cmd.ExecuteScalar();
            }
            finally
            {
                Connection.Close();
            }
        }
    }
}

此程式提供了兩個函式,GetData 函式需要兩個參數,一個是起始的筆數,一個是選取的筆數,利用這兩個參數加上 SQL Server 2005 新增的 RowNumber,便可以向資料庫要求傳回特定範圍的資料。那這兩個參數從何傳入的呢?當 GridView 向 ObjectDataSource 索取資料時,便會傳入這兩個參數,例如當 GridView 的 PageSize 是 10 時,第 1 頁時傳入的 startRowIndex 便是 10,maximumRows 就是 10,以此類推。第二個函式是 GetCount,對於 GridView 來說,她必須知道繫結資料的總頁數才能顯示 Pager 區,而此總頁數必須由資料總筆數算出,此時 GridView 會向 PageDataSource 要求資料的總筆數,而 PageDataSource 在 DataSource 控件支援分頁的情況下,會要求其提供總筆數,這時此函式就會被呼叫了。大致了解這個程式後,回到設計頁面,加入一個 ObjectDataSource 控件,於 SELECT 頁次選取帶 startRowIndex 及 maximumRows 參數的函式。

按下Next按紐後,精靈會要求我們設定參數值來源,請直接按下Finish來完成組態。

接著設定 ObjectDataSource 的 EnablePaging 屬性為 True,SelectCountMethod 屬性為 GetCount (對應了程式 4-8-26 中的 GetCount 函式),最後放入一個 GridView 控件,繫結至此 ObjectDataSource 後將 Enable Paging 打勾,就完成了手動分頁的 GridView 範例了。

在效能比上,手動分頁的效能在資料量少時絕對比 Cache 來的慢,但資料量大時,手動分頁的效能及記憶體耗費就一定比 Cache 來的好

http://www.microsoft.com/taiwan/msdn/columns/huang_jhong_cheng/ASP_NET_GridView.htm