| 方案 | 核心邏輯 | 優點 | 缺點 |
|---|---|---|---|
| 方案一 | NOT IN (SELECT TOP N*PageSize id...) | 邏輯直觀 | 大頁碼時子查詢記錄集大,記憶體壓力大 |
| 方案二 | ID > (SELECT MAX(id) FROM (SELECT TOP N*PageSize id...)) | 效率最高,利用索引求最大值 | 需 ID 連續且排序欄位唯一 |
| 方案三 | 游標 sp_cursoropen/fetch/close | 最通用,支援任意排序 | 效率最差 |
採用方案二時,若排序欄位 (ordercol) 有重複值,會導致資料遺漏。因為 ordercol >= MAX(...) 無法精確界定頁邊界。
SELECT TOP @PageSize *
FROM TestTable
WHERE ordercol >= (
SELECT MAX(ordercol)
FROM (SELECT TOP @PageSize*@PageNum ordercol FROM TestTable ORDER BY ordercol) t
)
AND id NOT IN (
SELECT TOP @PageSize*@PageNum id FROM TestTable ORDER BY ordercol
)
ORDER BY ordercol;
原理:先用排序欄位快速篩選候選集(效率高),再用 PK id 的 NOT IN 精確排除已翻頁資料(準確)。雖保留 NOT IN 缺點,但前置過濾大幅縮小掃描範圍,綜合效能可接受。
Recordset.Move > 2 秒WHERE id > @lastSeenId ORDER BY id) 或 Offset/Fetch (SQL 2012+)。