Какие стратегии пагинации можно использовать вместо LIMIT OFFSET?
Что проверяют
Для аналитика вопрос не про синтаксис SQL, а про то, сможете ли вы заложить пагинацию в требования и контракт API так, чтобы через год система не упёрлась в тормоза. Следом обычно спрашивают, как выбор отразится на интерфейсе и что делать, если данные меняются, пока пользователь листает список.
Как отвечать
Объясните проблему своими словами: при LIMIT 20 OFFSET 10000 база перебирает и выбрасывает десять тысяч строк, а при появлении новых записей список «съезжает», и пользователь видит дубли или пропуски.
Дальше варианты и что они значат для требований:
- курсорная (keyset) пагинация: сервер отдаёт страницу и
next_cursor, клиент присылает его в следующем запросе. Быстро на любой глубине и стабильно при вставках, но перейти на произвольную страницу нельзя. Подходит для лент, бесконечной прокрутки, мобильных клиентов и обмена между системами; - фиксированная сортировка: в спецификации явно указываете порядок и уникальное поле для равных значений, например
created_at desc, id desc, иначе курсор работать не будет; - снимок для отчётов: если нужен стабильный набор для выгрузки, его отдают фоновой задачей целиком, файлом;
- гибрид: номера страниц на первых нескольких страницах, дальше кнопка «показать ещё».
В OpenAPI это оформляется параметрами limit и cursor и полями ответа items, next_cursor, has_more. Для GraphQL есть готовая схема Relay Connections с first, after и pageInfo.
Где спотыкаются
Требуют одновременно номера страниц, общее количество и бесконечную прокрутку по миллионам строк. Придётся выбирать, и выбор нужно зафиксировать вместе с заказчиком.
Не описывают курсор как непрозрачный. Если в требованиях написано «передать id последней записи», клиенты начнут собирать его вручную, и сменить формат будет уже нельзя.
Забывают про фильтры. При смене фильтра или сортировки старый курсор недействителен, и в контракте должно быть сказано, что вернёт сервер: ошибку 400 или первую страницу.