Keyset Pagination (Phân trang theo khóa)
Phân trang đúng cách - thay thế LIMIT OFFSET cho page lớn.
Vấn đề #1: Thứ tự sắp xếp không ổn định
-- ❌ Sai: nhiều user cùng firstname có thể xuất hiện ở 2 page
SELECT * FROM users ORDER BY firstname LIMIT 20 OFFSET 40;
-- ✅ Đúng: thêm primary key để đảm bảo unique ordering
SELECT * FROM users ORDER BY firstname, lastname, user_id LIMIT 20 OFFSET 60;Vấn đề #2: OFFSET chậm với page lớn + data thay đổi
-- ❌ LIMIT OFFSET: page 1000 phải ĐỌC VÀ BỎ 999 × 30 = 29,970 rows
SELECT * FROM users ORDER BY firstname, lastname, id LIMIT 30 OFFSET 29970;
-- ✅ Keyset Pagination: dùng giá trị row cuối của trang trước làm điểm bắt đầu
SELECT * FROM users
WHERE (firstname, lastname, id) > ('Huy', 'Nguyen', 3150)
ORDER BY firstname, lastname, id
LIMIT 30;
-- Nhanh hơn RẤT nhiều cho page lớn (fast lookup + đọc 30 entries)
-- Nhược: không hỗ trợ nhảy thẳng đến page bất kỳVới index trên (firstname, lastname, id): database Fast Lookup đến vị trí row cuối trang trước rồi scan 30 entries - chi phí không đổi dù ở page 1 hay page 10,000. Data thêm/xóa giữa chừng cũng không làm lệch trang (không bị skip/duplicate như OFFSET).
Liên quan
- Quét một hướng - cơ chế bên dưới
- ORDER BY và Index - index phải khớp thứ tự sort
- SQL Execution Order - vì sao OFFSET lớn vẫn phải đọc hết