Вступить в клуб →
сложнаявопросPostgreSQL, JPA и производительность запросов

join fetch вместе с постраничной выборкой

Чтобы убрать N+1 в списке заказов, разработчик добавил fetch-выборку коллекции прямо в постраничный запрос:

@Query("select o from Order o join fetch o.items where o.status = :status")
Page<Order> findByStatus(@Param("status") Status status, Pageable pageable);

На тестовом стенде с сотней заказов всё быстро. В проде, где под фильтр попадает несколько сотен тысяч заказов, эндпоинт начинает отвечать десятки секунд, растёт потребление памяти, а в логах Hibernate появляется предупреждение о применении пагинации в памяти. Что происходит?

  • Пагинация корректно уходит в базу как LIMIT/OFFSET, а тормозит выгрузка позиций отдельными запросами — это остаточный N+1
  • Page требует дополнительного count-запроса, и именно он тратит всё время; помогает замена Page на Slice
  • Проблема в дубликатах заказов из-за join: достаточно добавить distinct, других последствий нет
  • Из-за join fetch коллекции Hibernate не может применить LIMIT к строкам результата: он вычитывает всю выборку и режет страницу в памяти

🔒 Проверка ответа — для участников клуба

  • Проверка ответа
  • Подсказка, если застряли
  • Разбор с объяснением, почему так
  • Прогресс по всем задачам и виртуальные собеседования
Зарегистрироваться →

Регистрация занимает минуту

Другие задачи раздела