Laravel Cursor Pagination


#Laravel#Pagination#Cursor Pagination#MySQL 效能

Laravel ORM 的三種 paginate 比較:

  使用情境 效能 總頁數 可跳頁
paginate 皆可 慢,每次都要 COUNT(*)
simplePaginate 不需知道資料總數時用 中等,資料多時慢
cursorPaginate 無限往下滾動的頁面 不可

cursorPaginate 是 Laravel 8.41 推出的新功能:https://laravel-news.com/cursor-pagination

以往無限滾動的分頁是用 simplePaginate,但 simplePaginate 底層使用的是 MySQL 中的 limit + offset,當頁數越後面時會讀取越慢,因為 offset 會把資料全都抓出來後再丟棄。

SELECT id, name FROM users LIMIT 10 OFFSET 0 -- 很快

SELECT id, name FROM users LIMIT 10 OFFSET 10000000 -- 超慢,會撈取 10000010 筆資料再丟棄前面的 10000000 

cursorPaginate 則是使用 orderBy 的欄位來查詢大/小於前一次的值,利用上一次的值往下或往上查詢。
但記得 orderBy 欄位要有索引,否則查詢還是慢,通常這欄位會是 Integer。 

SELECT id, name FROM users id > 10000000 ORDER BY id ASC LIMIT 10

因為是紀錄上一次查詢的值,所以上/下一頁網址就不會是 page=123 這種有序的網址,而是將頭尾數值加密放到 cursor 參數裡

http://localhost/users?cursor=eyJpZCI6MTUsIl9wb2ludHNUb05leHRJdGVtcyI6dHJ1ZX0

參考:
https://laravel.com/docs/9.x/pagination
https://laravel.com/api/9.x/Illuminate/Pagination/CursorPaginator.html
https://laravel-news.com/cursor-pagination
https://www.laravel-enlightn.com/blog/laravel-offset-vs-cursor-pagination