StudyCode
Почему offset-пагинация ломается на живых данных и как курсор «после id N» решает проблему дублей и пропусков.
Классическая пагинация — offset: «пропусти 4 записи, дай следующие 4». Работает, пока данные не меняются. Но данные живые!
Сценарий катастрофы (лента, свежее сверху или сортировка по id):
offset=4 — и видит последнюю запись прошлой страницы ещё раз (дубль). А при удалении — наоборот, запись проскочит незамеченной.| Offset | Курсор | |
|---|---|---|
| Запрос | «записи с позиции 4» | «записи ПОСЛЕ id 40» |
| Вставка/удаление | сдвигает страницы 💥 | не влияет ✅ |
| Прыжок на страницу 7 | можно | нельзя (только «дальше») |
| БД на глубоких страницах | медленно (перебирает offset строк) | быстро (индекс по id) |
Курсор — это указатель на последний увиденный элемент: «я остановился после id 40, продолжай оттуда». Позиции не важны — важен сам элемент.
// OFFSET: «дай записи с 5-й по 8-ю» — позиции сдвигаются при вставке
// SELECT * FROM items ORDER BY id LIMIT 4 OFFSET 4
// CURSOR: «дай записи ПОСЛЕ id 40» — вставки не сдвигают ничего
// SELECT * FROM items WHERE id > 40 ORDER BY id LIMIT 4
// Ответ курсорного API:
// { items: [...], nextCursor: 80 } ← есть ещё страницы
// { items: [...], nextCursor: null } ← это последняя