简体   繁体   中英

Hibernate warn durring query - left join fetch with Pageable

I have two classes wiht relation one to many. User :

@Entity
public class User {
    @Id
    private Long id;
    ...
    @OneToMany(mappedBy = "user", fetch = FetchType.LAZY)
    private Set<Note> notes = new HashSet<>();
    ...
}

and Note :

@Entity
public class Note {

    @Id
    private Long id;
    ...
    @ManyToOne(fetch = FetchType.LAZY)
    @JoinColumn(name = "user_id", nullable = false)
    private User user;
    ...
}

In the UserRepository I want to override findAll(Pageable<T> va1) method from PagingAndSortingRepository<T, ID> to avoid N+1 query problem. Everything works fine, with this code:

@Repository
public interface UserRepository extends JpaRepository<User, Long> {

    @Override
    @Query(value = "select distinct u from User u left join fetch u.notes")
    Page<User> findAll();
} 

But when I add pagination:

@Repository
public interface UserRepository extends JpaRepository<User, Long> {

    @Override
    @Query(value = "select distinct u from User u left join fetch u.notes",
            countQuery = "select count(u) from User u")
    Page<User> findAll(Pageable page);
}

I see warn in console:

HHH000104: firstResult/maxResults specified with collection fetch; applying in memory!

My question is, how to fix it?

When you want to join fetch child with pagination, Hibernate do SQL query without pagination means fetch full resultset. And do pagination in memory.

The easier way to fix this using two query

  • Fetch ids of user only with pagination
  • Then user join fetch notes with IN query by those ids

Code Example

@Query("select u.id from User u")
List<Long> getAllIds(Pageable page);

@Query(value = "select distinct u from User u left join fetch u.notes where u.id IN (:ids)")
List<User> findAll(@Param("ids")List<Long> ids);

This is a perfect use case for Blaze-Persistence .

Blaze-Persistence is a query builder on top of JPA which supports many of the advanced DBMS features on top of the JPA model. The pagination support it comes with handles all of the issues you might encounter.

It also has a Spring Data integration, so you can use the same code like you do now, you only have to add the dependency and do the setup: https://persistence.blazebit.com/documentation/entity-view/manual/en_US/index.html#spring-data-setup

Blaze-Persistence has many different strategies for pagination which you can configure. The default strategy is to inline the query for ids into the main query. Something like this:

select u 
from User u 
left join fetch u.notes 
where u.id IN (
  select u2.id
  from User u2
  order by ...
  limit ...
)
order by ...

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM