SQL пагинация: OFFSET или keyset по курсору

Категория: Postgresql · Язык: SQL · Обновлено:

Для простой пагинации SQL используют ORDER BY ... LIMIT ... OFFSET .... На больших таблицах глубокий OFFSET может быть медленным, потому что СУБД всё равно пропускает предыдущие строки. Keyset-пагинация продолжает выборку после последнего значения курсора и лучше подходит для прокрутки больших списков.

LIMIT и OFFSET с устойчивой сортировкой

SQL
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, чтобы соседние страницы не меняли порядок при одинаковой дате.

Продолжить после последней строки

SQL
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-запроса курсор должен содержать все поля сортировки в том же порядке. Составной индекс должен соответствовать фильтру и сортировке.

Метод

Подходит

LIMIT/OFFSET

Небольшие списки, переход на конкретную страницу

Keyset/cursor

Большие ленты и последовательная прокрутка

Почему страницы с OFFSET повторяют строки?

Если сортировка не уникальна, строки с одинаковым ключом могут менять порядок между запросами. Добавьте tie-breaker, например id, и используйте одинаковую сортировку на всех страницах.