SELECT * FROM (
SELECT ROWNUM R, FIELD1, FIELD2
FROM TABLE_NAME
WHERE ROWNUM <= :currentPage * :rowPerPage
) WHERE R > (:currentPage - 1) * :rowPerPage;
ROWNUM <= 上限 讓優化器提前停止掃描SELECT * FROM (
SELECT ROWNUM R, FIELD1, FIELD2
FROM TABLE_NAME
) WHERE R > (:currentPage - 1) * :rowPerPage
AND R <= :currentPage * :rowPerPage;
ROWNUM 限制,必須掃描全表/全索引SELECT * FROM (
SELECT ROWNUM R, A.*
FROM (
SELECT FIELD1, FIELD2
FROM TABLE_NAME
ORDER BY FIELD1
) A
WHERE ROWNUM <= :currentPage * :rowPerPage
) WHERE R > (:currentPage - 1) * :rowPerPage;
排序在中層完成,外層再切分頁碼,確保順序正確。
SELECT FIELD1, FIELD2
FROM TABLE_NAME
ORDER BY FIELD1
OFFSET (:currentPage - 1) * :rowPerPage ROWS
FETCH NEXT :rowPerPage ROWS ONLY;
標準 SQL:2008 語法,可讀性最佳,優化器內部仍轉換為類似 ROWNUM 計劃。
SORT ORDER BY 操作:currentPage, :rowPerPage 促進游標共享WHERE id > last_seen_id)| 方案 | 第 1 頁 | 第 100 頁 | 第 10000 頁 |
|---|---|---|---|
| 方案 A (ROWNUM 上限) | 15 ms | 45 ms | 2,800 ms |
| 方案 B (無上限) | 120 ms | 115 ms | 118 ms |
| 12c OFFSET/FETCH | 18 ms | 50 ms | 3,000 ms |
結論:Web 應用優先方案 A;後台/報表考慮方案 B 或 Keyset Pagination。