Ответ вслух Senior Spring Data JPA обновлено

Пагинация больших списков

Вопрос

Как вы делаете пагинацию списка из десятков миллионов записей в Spring Data?

Попробуйте сами

Ответьте вслух за 2 минуты, как на собесе. Потом сверьтесь с тезисами: что прозвучало, а что нет.

Показать ответ и разбор

Коротко

Для небольших таблиц хватает Page и PageRequest. На десятках миллионов две проблемы.

Что должно прозвучать в ответе

  • 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 ошибок.