應用層分頁指一次性從資料庫撈回較大範圍的資料集,快取於伺服器記憶體(DataSet、List<T>、Session、Cache),再由前端控制項逐頁顯示。優點是後續翻頁無需再查資料庫,回應極快;缺點是首次查詢耗時較長,且佔用應用程式記憶體,不適合極大資料集。
ASP.NET 2.0 起,GridView 內建分頁功能。搭配 SqlDataSource/ObjectDataSource 的 EnableCaching="true",資料源首次查詢後快取於伺服器,後續分頁直接從快取讀取。
<asp:SqlDataSource ID="srcProducts" runat="server"
ConnectionString="<%$ ConnectionStrings:Northwind %>"
SelectCommand="SELECT ProductID, ProductName, UnitPrice FROM Products"
EnableCaching="true" CacheDuration="300" />
<asp:GridView ID="gvProducts" runat="server" DataSourceID="srcProducts"
AllowPaging="true" PageSize="10" />
.NET 3.5 引入 DataPager,可搭配 ListView 使用,提供更靈活的分頁 UI(Numeric、NextPrevious、Template),並支援自訂分頁邏輯。
<asp:ListView ID="lvProducts" runat="server" DataSourceID="srcProducts">
<LayoutTemplate><table><tr id="itemPlaceholder" runat="server" /></table></LayoutTemplate>
<ItemTemplate><tr><td><%# Eval("ProductName") %></td></tr></ItemTemplate>
</asp:ListView>
<asp:DataPager ID="dpProducts" runat="server" PagedControlID="lvProducts" PageSize="10">
<Fields>
<asp:NumericPagerField ButtonCount="5" />
</Fields>
</asp:DataPager>
若資料量適中(如 < 10 萬筆),可一次 ToList() 進記憶體,再用 LINQ Skip()/Take() 分頁;或直接在 IQueryable 上翻頁(資料庫端分頁)。
// 記憶體分頁(資料已載入 List)
var pageData = allProducts.Skip((pageIndex-1)*pageSize).Take(pageSize).ToList();
// 資料庫端分頁(IQueryable,產生 SQL OFFSET/FETCH)
var pageData = dbContext.Products
.OrderBy(p => p.ProductID)
.Skip((pageIndex-1)*pageSize)
.Take(pageSize)
.ToList();
| 場景 | 建議方案 |
|---|---|
| 中小型資料集、頻繁翻頁、資料較少變動 | 應用層快取 + GridView/DataPager |
| 大型資料集、即時性要求高 | 資料庫端分頁(OFFSET/FETCH 或 ROW_NUMBER) |
| 彈性 UI、需自訂分頁樣板 | ListView + DataPager |
| 現代專案、使用 EF Core | LINQ Skip/Take(自動轉譯為 SQL 分頁) |
CacheDuration、SlidingExpiration)。OutputCache 或分散式快取。