首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> .NET 網頁程式設計 >> ASP.NET 基礎 >> 關於ASP.NET

ASP.NET 高效能分頁:存儲過程 + 游標分頁實現大數據集秒級查詢

     編輯:關於ASP.NET

為何需要高效能分頁

傳統 `DataSet`/`DataTable` 全量載入再分頁,資料量超過萬筆即嚴重拖慢記憶體與回應時間。真正的高效能分頁必須在 **資料庫層** 只取得當頁資料。

SQL Server 存儲過程:游標式分頁 (SQL 2000/2005 相容)

CREATE PROCEDURE dbo.Tag_Page_Name_Select
 @MaxPageSize INT,      -- 每頁筆數
 @PageNum INT,          -- 當前頁碼 (1-based)
 @Count INT OUTPUT      -- 總筆數
AS
BEGIN
 SET NOCOUNT ON;

 DECLARE @Name NVARCHAR(50), @Cursor INT;

 -- 1. 取得總筆數
 SELECT @Count = COUNT(*) FROM [view_tag];

 -- 2. 計算游標起始位置 (1-based)
 SET @Cursor = @MaxPageSize * (@PageNum - 1) + 1;

 -- 3. 處理頁碼超出範圍:自動導向最後一頁
 IF @Cursor > @Count
 BEGIN
 IF @Count % @MaxPageSize = 0 -- 尾頁剛好滿頁
 BEGIN
 IF @Cursor > @MaxPageSize
 SET @Cursor = @Count - @MaxPageSize + 1;
 ELSE
 SET @Cursor = 1;
 END
 ELSE -- 尾頁不滿
 SET @Cursor = @Count - (@Count % @MaxPageSize) + 1;
 END

 -- 4. 移動游標至目標起始列
 SET ROWCOUNT @Cursor;
 SELECT @Name = tag_Name FROM [view_tag] ORDER BY tag_Name;

 -- 5. 取得當頁資料
 SET ROWCOUNT @MaxPageSize;
 SELECT * FROM [view_tag] WHERE tag_Name >= @Name ORDER BY tag_Name;

 -- 6. 重置 ROWCOUNT
 SET ROWCOUNT 0;
END

現代寫法:OFFSET/FETCH (SQL Server 2012+)

CREATE PROCEDURE dbo.GetPagedData
 @PageSize INT, @PageNumber INT, @TotalCount INT OUTPUT
AS
BEGIN
 SELECT @TotalCount = COUNT(*) FROM LargeTable;

 SELECT * FROM LargeTable
 ORDER BY Id
 OFFSET (@PageNumber - 1) * @PageSize ROWS
 FETCH NEXT @PageSize ROWS ONLY;
END

ASP.NET 呼叫端程式碼

public class PagedResult
{
 public List Items { get; set; }
 public int TotalCount { get; set; }
 public int PageSize { get; set; }
 public int PageNumber { get; set; }
 public int TotalPages => (int)Math.Ceiling((double)TotalCount / PageSize);
}

public PagedResult GetTags(int pageSize, int pageNumber)
{
 using (SqlConnection conn = new SqlConnection(connStr))
 using (SqlCommand cmd = new SqlCommand("Tag_Page_Name_Select", conn))
 {
 cmd.CommandType = CommandType.StoredProcedure;
 cmd.Parameters.AddWithValue("@MaxPageSize", pageSize);
 cmd.Parameters.AddWithValue("@PageNum", pageNumber);
 SqlParameter totalParam = cmd.Parameters.Add("@Count", SqlDbType.Int);
 totalParam.Direction = ParameterDirection.Output;

 conn.Open();
 using (SqlDataReader dr = cmd.ExecuteReader())
 {
 var list = new List();
 while (dr.Read())
 {
 list.Add(new Tag
 {
 Id = dr.GetInt32(0),
 Name = dr.GetString(1)
 });
 }
 return new PagedResult
 {
 Items = list,
 TotalCount = (int)totalParam.Value,
 PageSize = pageSize,
 PageNumber = pageNumber
 };
 }
 }
}

前端分頁 UI (Bootstrap 範例)

效能比較

方案資料量 10萬資料量 100萬記憶體網路傳輸
全量載入 + PagedDataSource~2 秒OOM / >30 秒高 (全表)全表
存儲過程分頁 (ROWCOUNT/OFFSET)< 50ms< 100ms極低 (單頁)單頁

進階優化技巧

  • 索引覆蓋:`ORDER BY` 欄位建立索引,`SELECT` 欄位包含於索引 (Covering Index),避免 Key Lookup。
  • Keyset Pagination (Seek Method):`WHERE Id > @LastSeenId ORDER BY Id LIMIT @PageSize`,適合無限捲動,避免深分頁效能劣化。
  • 快取總筆數:總筆數變化慢,快取 5-10 分鐘,減少 `COUNT(*)` 開銷。
  • 非同步執行:`ExecuteReaderAsync`、`ReadAsync` 不阻塞執行緒。

總結

高效能分頁核心在於 **資料庫層面只取需要的資料**。SQL Server 2012+ 請直接使用 `OFFSET/FETCH`;舊版本用 `ROWCOUNT` 游標法或 `ROW_NUMBER()` CTE。前端配合快取總頁數、Keyset 分頁,可支撐億級資料秒級翻頁。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved