Обновить

Комментарии 13

А если в качестве ключа таблицы используется не int, а uuid?

Отличный вопрос, потому что многие отказываются от keyset не зная, что делать в таком случае)
Я бы сделал так -

1) Оставил UUID как первичный ключ (для API, бизнес-логики)
2) Добавил техническое поле (например, long seq_id) и использовать его для пагинации.

Это очень распространённый паттерн: публичный id — UUID, внутренний ordering id — последовательный bigint. И обязательно нужно заиндексировать seq_id

Пример SQL в таком случае:

SELECT id, name, seq_id
FROM users
WHERE seq_id > 100
ORDER BY seq_id
LIMIT 10;


Самая главная проблема такого подхода в том, что у long seq_id будет лимит значений, который может исчерпаться, ведь long не резиновый)

Рассмотреть переход на uuid v7.

О, зумеры узнали что offset и count на больших объемах данных работают медленно :)

Нужно индексировать поля самой частой сортировки и всё равно делать доп. сортировку по id.

Пример сортировка по created_at:

Ты хочешь показывать пользователей по дате создания:

SELECT id, name, created_at
FROM users
WHERE (created_at, id) > (:lastCreatedAt, :lastId)
ORDER BY created_at, id
LIMIT 100;

И под это создаёшь индекс:

CREATE INDEX idx_users_created_at_id ON users(created_at, id);

Если сортировать только по created_at, то:

  • при одинаковом created_at порядок строк не детерминирован,

  • PostgreSQL может перепрыгнуть или дублировать строки при переходе между страницами.

Добавление id в сортировку делает порядок уникальным и стабильным.

Конечно, не всегда удобно следить за частотой выборки и добавлять кучу индексов, но это стоит того)

Хороший вопрос. Индексация, вспомогательные таблицы, ленивое удаление, ночные Batch Recalculation, триггеры с инкрементальным обновлением индексов, и прочие незабываемые приключения. По каждому способу можно такую же статью написать. А по их комбинации - книгу.

Ну а если серьезно, то каждый случай индивидуален и определяется структурой домена и объемом данных.

Попытка изобрести серебряную пулю для RDB такое же частное явление, как разработка вечных двигателей у мальчиков до изучения физики. И такое же безнадежное. У девочек такие приступы намного реже, с чем их можно только поздравить ;)

Можно рассмотреть создание фронт-бека к базе в виде монги или эластика, если требуется глубокая пагинация, потому что там кешируется набор результатов и эта проблема исчезает. Так же нужно в принципе задаться вопросом: а зачем юзеру нужна глубокая пагинация в большом резалтсете, чтобы посмотреть тысячу записей глазами, зачем? Может быть стоит просто выгрузить эту тысячу записей сразу на клиент за один запрос и уже на нем изучить результат?

все поля, участвующие в WHERE и ORDER BY, должны быть покрыты индексом

...

выполнит seq scan (чтение всей таблицы),

Расскажите на примере where id > 100500 and role = 'DEV' зачем БД делать seq scan, если никаких индексов нет (кроме того что на id висит по-умолчанию)?

Странно в статье про keyset и Spring не упомянуть Scrolling.

Прошу прощения, я не так выразился, я имел ввиду поле в where которое отвечает за выборку keyset. Where id > 100, например, что дальше, конечно не нужно. Поправил в статье, спасибо)

Хорошо бы конечно показывать не только примеры запросов, которые получаются под капотом JPA, но и их планы, чтобы показать наглядно что меняется, и уже на основании этого делать выводы.. иначе фактически нужно просто поверить что этот запрос лучше чем тот

Зарегистрируйтесь на Хабре, чтобы оставить комментарий

Публикации