Пагинация больших списков
Вопрос
Как вы делаете пагинацию списка из десятков миллионов записей в Spring Data?
Попробуйте сами
Ответьте вслух за 2 минуты, как на собесе. Потом сверьтесь с тезисами: что прозвучало, а что нет.
Показать ответ и разбор
Коротко
Что должно прозвучать в ответе
Page делает count, Slice нет
OFFSET линейно дорожает с глубиной
Keyset (seek) пагинация по индексированному ключу, ScrollPosition и Window
Стабильная сортировка с уникальным ключом
Нельзя join fetch коллекций с пагинацией
Проекции вместо сущностей
Что могут спросить следом
- Как перейти на произвольную страницу при keyset?
- Как посчитать общее число записей дёшево?
Разбор
Для небольших таблиц хватает Page и PageRequest. На десятках миллионов две проблемы. Первая: Page делает count, который на большой таблице с фильтрами медленный, поэтому беру Slice или показываю «примерно N» из статистики. Вторая: OFFSET линейно дорожает, страница миллион заставляет базу прочитать и выбросить миллион строк. Решение: keyset-пагинация, когда клиент присылает последнее значение ключа сортировки, а запрос делает where (created_at, id) < (:ts, :id) order by created_at desc, id desc limit 20 по составному индексу. В Spring Data 3.1+ это ScrollPosition.keyset() и Window. Сортировка обязательно с уникальным ключом в конце, иначе записи будут прыгать между страницами. Для списка выбираю проекции, а коллекции не fetch-джойню, подгружаю отдельным запросом по id страницы.
Ответьте сами, а не прочитайте
В тренажёре вопрос попадёт в повторения и вернётся, когда начнёт забываться. Плюс билеты с зачётом: 20 вопросов, не больше 2 ошибок.