OFFSET 分頁的總成本是 O(頁數²),cursor 分頁才是 O(頁數)
資料庫沒有「直接跳到第 999001 筆」這種能力。
OFFSET n的語意是掃過前面 n 筆、一筆一筆丟掉,才開始回傳你要的那一頁。
OFFSET:每一頁都要把前面重走一遍
SELECT ... ORDER BY id LIMIT 1000 OFFSET 999000;- 第 1 頁:丟 0 筆
- 第 500 頁:丟 49.9 萬筆
- 第 1000 頁:丟 99.9 萬筆
單頁成本隨頁碼線性成長,所以走完全部頁的總工作量是 O(頁數²)。100 萬筆切成 1000 頁,總共要掃約 5 億次。
cursor(keyset):把「跳過」換成「從哪裡開始」
SELECT ... WHERE id > :last_id_of_previous_page ORDER BY id LIMIT 1000;每一頁都是「從游標往後讀 1000 筆就走」,不用管前面有幾筆。每頁成本固定,總工作量 O(頁數)。
代價:游標欄位要有索引且能穩定排序(通常是主鍵或 (sort_key, id) 複合鍵),而且不能隨機跳到第 N 頁——只能一頁接一頁往前走。這對背景工作剛好不是問題。