Комментарии 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? Как ускорить запрос?
Нужно индексировать поля самой частой сортировки и всё равно делать доп. сортировку по 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.
Хорошо бы конечно показывать не только примеры запросов, которые получаются под капотом JPA, но и их планы, чтобы показать наглядно что меняется, и уже на основании этого делать выводы.. иначе фактически нужно просто поверить что этот запрос лучше чем тот

Как дефолтная пагинация в Spring сломала проект и как это починить