DataGrid是一個功能非常強大的ASP.NET Web服務器端控件,它除了能夠方便地按各種方式格式化顯示表格中的數據,還可以對表格中的數據進行動態的排序、編輯和分頁。使Web開發人員從繁瑣的代碼中解放。實現DataGrid的分頁功能一直是很多初學ASP.NET的人感到棘手的問題,特別是自定義分頁功能,實現方法多種多樣,非常靈活。本文將向大家介紹一種DataGird控件在Access數據庫下的快速分頁法,幫助初學者掌握DataGrid的分頁技術。
目前的分頁方法
DataGrid內建的分頁方法是使用諸如“SELECT * FROM <TABLE>”的SQL語句從數據庫表中取出所有的記錄到DataSet中,DataGrid控件綁定到該DataSet之後,它的自動分頁功能會幫你從該DataSet中篩選出當前分頁的數據並顯示出來,其他沒有用的數據將被丟棄。
還有一種方法是使用自定義分頁功能,先將DataGrid的AllowCustomPaging屬性設置為True,再利用DataAdapter的Fill方法將數據的篩選工作提前到填充DataSet時,而不是讓DataGrid幫你篩選:
public int Fill (
DataSet dataSet, //要填充的 DataSet。
int startRecord, //從其開始的從零開始的記錄號。
int maxRecords, //要檢索的最大記錄數。
string srcTable //用於表映射的源表的名稱。
);
該方法首先將來自查詢處的結果填充到DataSet中,再將不需要顯示的數據丟棄。當然,自定義分頁功能需要完成的事情還不止這些,本文將在後面詳細介紹。
以上兩種方法的工作原理都是先從數據庫中取出所有的記錄,然後篩選出有用的數據顯示出來。可見,兩種方法的效率基本上是一致的,因為它們在數據訪問階段並沒有采取有效的措施來減少Access對磁盤的訪問次數。對於小數量的記錄,這種開銷可能是比較小的,如果針對大量數據的分頁,開銷將會非常巨大,從而導致分頁的速度非常的慢。換句話說,就算每個DataGrid分頁面要顯示的數據只是一個擁有幾萬條記錄的數據庫表的其中10條,每次DataGrid進行分頁時還是要從該表中取出所有的記錄。
很多人已經意識到了這個問題,並提出了解決方法:用自定義分頁,每次只從數據庫中取出要顯示的數據。這樣,我們需要在SQL語句上下功夫了。由於Access不支持真正的存儲過程,在編寫分頁算法上就沒有SQL Server那麼自由了。SQL Server可以在存儲過程中利用臨時表來實現高效率的分頁算法,受到了廣泛的采用。而對於Access,我們必須想辦法在一條SQL語句內實現最高效的算法。
用一條SQL語句取得某段數據的方法有好幾種。算法不同,效率也就不同。我經過粗略的測試,發現效率最差的SQL語句執行時耗費的時間大概是效率最高的SQL語句的3倍!而且這個數值會隨著記錄總數的增加而增加。下面將介紹其中兩條常用的SQL語句。
為了方便接下來的討論,我們先約定如下:
變量 說明 變量 說明 @PageSize 每頁顯示的記錄總數 @MiddleIndex 中間頁的索引 @PageCount 分頁總數 @LastIndex 最後一頁的索引 @RecordCount 數據表的記錄總數 @TableName 數據庫表名稱 @PageIndex 當前頁的索引 @PrimaryKey 主鍵字段名稱 @FirstIndex 第一頁的索引 @QueryFields 要查詢的字段集變量
定義
@PageCount (int)Math.Ceiling((double)@RecordCount / @PageSize) @FirstIndex 0 @LastIndex @PageCount – 1 @MiddleIndex (int)Math.Ceiling((double)@PageCount / 2) – 1先讓我們看看效率最差的SQL語句:
SELECT TOP @PageSize * FROM @TableName
WHERE @PrimaryKey NOT IN (
SELECT TOP @PageSize*@PageIndex @PrimaryKey FROM @TableName
ORDER BY @PrimaryKey ASC
) ORDER BY @PrimaryKey ASC
這條SQL語句慢就慢在NOT IN這裡,主SELECT語句遍歷的每個@PrimaryKey的值都要跟子SELECT語句的結果集中的每一個@PrimaryKey的值進行比較,這樣時間復雜度非常大。這裡不得不提醒一下大家,平時編寫SQL語句時應該盡量避免使用NOT IN語句,因為它往往會增加整個SQL語句的時間復雜度。
另一種是使用了兩個TOP和三個ORDER BY的SQL語句,如下所示:
SELECT * FROM (
SELECT TOP @PageSize * FROM (
SELECT TOP @PageSize*(@PageIndex+1) * FROM @TableName
ORDER BY @PrimaryKey ASC
) TableA ORDER BY @PrimaryKey DESC
) TableB ORDER BY @PrimaryKey ASC
這條SQL語句空間復雜度比較大。如果要顯示的分頁面剛好是最後一頁,那麼它的效率比直接SELECT出所有的記錄還要低。因此,對於分頁算法,我們還應該具體情況具體分析,不能一概而論。下面將簡單介紹一下相關概念,如果您對主鍵和索引非常熟悉,可以直接跳過。
有關主鍵和索引的概念
在 ACCESS中,一個表的主鍵(PRIMARY KEY,又稱主索引)必然是唯一索引(UNIQUE INDEX),它的值是不會重復的。除此之外,索引依據索引列的值進行排序,每個索引記錄包含著一個指向它所引用的數據行的指針,這對ORDER BY的執行非常有幫助。我們可以利用主鍵這兩個特點來實現對某條記錄的定位,從而快速地取出某個分頁上要顯示的記錄。
舉個例子,假設主鍵字段為INTEGER型,在數據庫表中,記錄的索引已經按主鍵字段的值升序排好(默認情況下),那麼主鍵字段值為“11”的記錄的索引,肯定剛好在值為“12”的記錄的索引前面(假設數據庫表中存在主鍵的值為“12”的記錄)。如果主鍵字段不具備UNIQUE約束,數據庫表中將有可能存在兩個或兩個以上主鍵字段的值為“11”的記錄,這樣就無法確定這些記錄之間的前後位置了。
下面就讓我們看看如何利用主鍵來進行數據的分段查詢吧。