SELECT * FROM t LIMIT 100000, 20 需掃描並丟棄前 10 萬列,深分頁效能線性惡化。
SELECT * FROM articles WHERE cat_id=5 ORDER BY id DESC LIMIT 20 OFFSET 100000;
filesort、記憶體壓力大。利用唯一排序鍵 (PK/UK) 記住上一頁邊界值:
-- 第一頁
SELECT * FROM articles WHERE cat_id=5 ORDER BY id DESC LIMIT 20;
-- 下一頁 (假設上一頁最小 id = 99980)
SELECT * FROM articles WHERE cat_id=5 AND id < 99980 ORDER BY id DESC LIMIT 20;
-- 上一頁 (假設上一頁最大 id = 100000)
SELECT * FROM articles WHERE cat_id=5 AND id > 100000 ORDER BY id ASC LIMIT 20;
資料庫端維護伺服器端游標:
-- MySQL
DECLARE cur CURSOR FOR SELECT * FROM articles WHERE cat_id=5 ORDER BY id DESC;
OPEN cur;
FETCH NEXT 20 FROM cur; -- 重複呼叫
| 分頁深度 | OFFSET (ms) | Keyset (ms) | 游標 (ms) |
|---|---|---|---|
| 第 1 頁 | 5 | 4 | 6 |
| 第 100 頁 | 45 | 4 | 5 |
| 第 10,000 頁 | 3,200 | 5 | 6 |
-- 精確但較慢
SELECT COUNT(*) FROM articles WHERE cat_id=5;
-- 近似快速 (MyISAM/InnoDB 統計資訊)
SHOW TABLE STATUS LIKE 'articles'; -- Rows 欄位
-- 應用層快取總數,定期異步更新
next_cursor (Base64 編碼邊界值) 而非 page_number。ORDER BY created_at DESC, id DESC) 需將複合值編碼為游標。Keyset 分頁是大資料集高效分頁的標準解法,犧牲「任意跳頁」換取穩定低延遲。