SQL пагинация: OFFSET или keyset по курсору
Для простой пагинации SQL используют ORDER BY ... LIMIT ... OFFSET .... На больших таблицах глубокий OFFSET может быть медленным, потому что СУБД всё равно пропускает предыдущие строки. Keyset-пагинация продолжает выборку после последнего значения курсора и лучше подходит для прокрутки больших списков.
LIMIT и OFFSET с устойчивой сортировкой
CREATE TEMP TABLE posts (id int, created_at date);
INSERT INTO posts VALUES (1, '2026-01-01'), (2, '2026-01-01'), (3, '2026-01-02');
SELECT id, created_at FROM posts
ORDER BY created_at, id
LIMIT 2 OFFSET 0;Добавьте уникальный столбец id в ORDER BY, чтобы соседние страницы не меняли порядок при одинаковой дате.
Продолжить после последней строки
WITH posts(id, created_at) AS (
VALUES (1, DATE '2026-01-01'), (2, DATE '2026-01-01'), (3, DATE '2026-01-02')
)
SELECT id, created_at FROM posts
WHERE (created_at, id) > (DATE '2026-01-01', 2)
ORDER BY created_at, id
LIMIT 2;Для keyset-запроса курсор должен содержать все поля сортировки в том же порядке. Составной индекс должен соответствовать фильтру и сортировке.
Метод | Подходит |
|---|---|
| Небольшие списки, переход на конкретную страницу |
Keyset/cursor | Большие ленты и последовательная прокрутка |
Почему страницы с OFFSET повторяют строки?
Если сортировка не уникальна, строки с одинаковым ключом могут менять порядок между запросами. Добавьте tie-breaker, например id, и используйте одинаковую сортировку на всех страницах.