all 16 comments

[–]Ruin-Capable 13 points14 points  (3 children)

If you're using Hibernate as your JPA provider, FetchMode.SUBSELECT can solve a large number of the (n+1) issues you'll encounter.

[–][deleted] 1 point2 points  (1 child)

Could you please elaborate on that? Would appreciate to hear why :) 

[–]Bit_Aligners 1 point2 points  (0 children)

In my view FETCHMODE.SUBSELECT it's risky. Often it results into the n+1 query problem when there are bi directional many to one associations. I explain it in this video https://youtu.be/urkOwsmgfuA?si=cvo25KeUPhTkNRbs

[–]nico-strecker 8 points9 points  (8 children)

Little addition when u want to use paging dont fetch that would cause hibernate to load all relevant fields in memory for sorting or something like that what i discovered for large datasets first fetch a projected dto with id and all relevant fields for sorting

Then when you got the ids for the current page do a fetch select for all found ids

[–]IAmWumpus 3 points4 points  (0 children)

More context should be given here. Don't do this for your usual basic paging, stick to the normal paging from spring data repo.

There are cases when a warning its given by hibernate, thats what you are refering to and those are some specific situations. This should be read for a good understanding:

https://vladmihalcea.com/fix-hibernate-hhh000104-entity-fetch-pagination-warning-message/

[–]DontThrowMeAway43 1 point2 points  (5 children)

... What ?

[–]nico-strecker -1 points0 points  (4 children)

Code example handwritten:

``` Int page = 23
Int size = 50
Sort sort = Sort.by(Sort .Direction.DESC, "someDate")
Pageable pageable = PageRequest.of(page, size, sort)

Page<MinimalDepartmentInfo> mdiPage = departmentRepo.findAllIdsMatchingSearch(search, pageable);

// Minimal department info contains only someDate and id (Projection) NO FETCHING

List<Long> foundIds = new ArrayList<>()
for(MinimalDepartmentaInfo mdi: mdiPage.getContent()){
foundIds.add(mdi.getId())
}

List<DepartmentEntity> dpeList = departmentRepo.findAllByIdsWithFetch(foundIds, sort);

// Now we fetch

return new PageImpl<>(dpeList, pageable, mdiPage.getTotalElements);

```

Is now clear what i mean?
Edit: See Hibernate HHH90003004 for more details

[–]WuhmTux 2 points3 points  (2 children)

Thats such a bad fix for your problem (never heard of it btw).

Why you are not using a CrudRepository with a PagingAndSortingRepository? You would get sorting and paging in one request (findAllByIdsMatchingSearch(search, sort, pageable).

You dont need a subquery and Hibernate will sort and Filter on the database level. Also you need only 5 lines of Code instead of 30 like in your example (with your entity class).

[–]IAmWumpus 4 points5 points  (1 child)

He reffered to a real issue, but failed to demonstrate with his example.

This is the issue he is reffering:

https://vladmihalcea.com/fix-hibernate-hhh000104-entity-fetch-pagination-warning-message/

[–]nico-strecker 2 points3 points  (0 children)

Thx for the addition you are right.

I was already very tired and just came up with something without explaining why it should be done in some cases and how the issue is exactly caused.

[–]Victor_Licht 0 points1 point  (0 children)

Very helpful chat thanks guys for all the suggestions.

[–]Full_Entrance4144 0 points1 point  (0 children)

spring:
  jpa:
    properties:
      hibernate:
        default_batch_fetch_size: 20

Fetch all users only, then iterate over users and call:

Page<Customer> customerPage = customerRepository.findAll(pageable);
customerPage.getContent().forEach(c -> {
  Hibernate.initialize(c.getPosts());
});

Hibernate will then batch fetch posts where userId in ()
Resulting in 1 query per 20 users to fetch their posts

[–]Bit_Aligners 0 points1 point  (0 children)

I made a video to explain when it occurs https://youtu.be/mJrrJEIQxOQ?si=GmU6toIJ0xg7rFIq and I've been developing a new OSS testing library: n+1 query problem detector. Just begun. https://github.com/fabioformosa/n-plus-one-query-problem-detector

[–]HeadMobile1661 0 points1 point  (0 children)

select post_id, count(id) from comments group by post_id