Vì ORDER BY không xác định (non-deterministic) khi nhiều dòng có cùng giá trị sắp xếp.
SQL không hứa giữ nguyên thứ tự giữa các dòng bằng nhau, nên hai lần chạy có thể xếp chúng khác nhau — dòng ở cuối trang 1 có thể xuất hiện lại ở đầu trang 2, hoặc bị bỏ qua.
sql
-- nhieu bai cung created_at -> thu tu khong on dinh
SELECT * FROM posts ORDER BY created_at DESC LIMIT 20 OFFSET 20;
-- sua: them tie-breaker duy nhat
SELECT * FROM posts ORDER BY created_at DESC, id DESC LIMIT 20 OFFSET 20;Quy tắc: mọi truy vấn có LIMIT phải ORDER BY trên một tổ hợp cột duy nhất — thường là thêm khoá chính vào cuối.
Hai vấn đề còn lại mà tie-breaker không giải quyết:
- Dữ liệu thay đổi giữa hai lần gọi trang (có bài mới chèn vào) vẫn gây lệch. Cách xử lý là phân trang theo con trỏ (WHERE (created_at, id) < (:last_at, :last_id)).
- OFFSET lớn vẫn chậm vì database phải đọc rồi bỏ đi OFFSET dòng đầu tiên.