分頁是 Web 應用常見需求,主要有兩大技術路線:游標分頁(Scrollable ResultSet)與 SQL 分頁(LIMIT/TOP/ROW_NUMBER)。本文詳細比較兩者原理、效能與適用場景,並修正常見誤區。
一次撈取大量資料(如 10,000 筆)至記憶體,再用 ResultSet.absolute(pos) 或 next() 定位頁面區間。
Connection conn = ...;
Statement stmt = conn.createStatement(
ResultSet.TYPE_SCROLL_INSENSITIVE,
ResultSet.CONCUR_READ_ONLY);
ResultSet rs = stmt.executeQuery(sql);
rs.absolute(11); // 直接跳到第 11 筆
// 依次取出 10 筆
缺點: 資料量大時佔用客戶端/中間層大量記憶體,網路傳輸成本高,**不推薦用於生產環境大數據量場景**。
由資料庫引擎僅回傳當頁資料,效能最佳。
SELECT TOP @page_size *
FROM t_test
WHERE id NOT IN (
SELECT TOP @skip id FROM t_test ORDER BY id DESC
)
ORDER BY id DESC
@skip = @page_size * (@page - 1)
SELECT * FROM t_test ORDER BY id LIMIT @page_size OFFSET @skip
SELECT * FROM (
SELECT t.*, ROW_NUMBER() OVER (ORDER BY id) rn FROM t_test t
) WHERE rn BETWEEN @start AND @end
iBATIS、Hibernate、MyBatis 等均封裝了 SQL 級分頁(非游標),配置 RowBounds 或 setFirstResult/setMaxResults 即可,底層自動轉換為對應方言的 LIMIT/TOP/ROW_NUMBER 語法。
| 場景 | 推薦方案 |
|---|---|
| 資料量 < 1 萬筆、簡單原型 | 游標分頁可接受 |
| 大數據量、高併發、生產環境 | **SQL 原生分頁** |
| 使用 ORM 框架 | 直接用框架內建分頁 API |