Home > Blockchain >  Why does subselect make 2 queries instead of one?
Why does subselect make 2 queries instead of one?

Time:09-17

I have a simple Restaurant Entity that has a List of Votes ( some fields and methods are omitted for brevity ).

public class Restaurant extends AbstractNamedEntity {
    @OneToMany(mappedBy = "restaurant", cascade = CascadeType.ALL, orphanRemoval = true)
    @JsonManagedReference
    @Fetch(FetchMode.SUBSELECT)
    private List<Vote> votes;
}

Here is another side of the relationship

 public class Vote extends AbstractBaseEntity {
    @ManyToOne
    @JsonBackReference
    private Restaurant restaurant;
}

When I try to fetch data using Spring data JPA findAll() method and then convert it to DTOs

  public static RestaurantResponseDTO toRestaurantDto(Restaurant restaurant) {

        return new RestaurantResponseDTO(restaurant.getId(), restaurant.getName(),
                restaurant.getAddress(), getRestaurantVoteCount(restaurant));
    }
    public static long getRestaurantVoteCount(Restaurant restaurant) {
    var votes = restaurant.getVotes();
    if (votes == null) return 0;
    return  votes.stream().filter(vote -> vote.getVoteDate().equals(LocalDate.now())).count();
}

these are the SQLs I have:

Hibernate: 
select
    restaurant0_.id as id1_1_,
    restaurant0_.name as name2_1_,
    restaurant0_.address as address3_1_ 
from
    restaurant restaurant0_

Hibernate: 
select
    votes0_.restaurant_id as restaura3_4_1_,
    votes0_.id as id1_4_1_,
    votes0_.id as id1_4_0_,
    votes0_.restaurant_id as restaura3_4_0_,
    votes0_.user_id as user_id4_4_0_,
    votes0_.vote_date as vote_dat2_4_0_ 
from
    vote votes0_ 
where
    votes0_.restaurant_id in (
        select
            restaurant0_.id 
        from
            restaurant restaurant0_
    )

I thought that Subselect needs only 1, why do I have 2?

CodePudding user response:

Actually, what you see is expected hibernate behavior. See this section of the hibernate documentation.

Hibernate is going to avoid the N 1 query issue by generating a single SQL statement to initialize all votes collections for all Restaurant entities that were previously fetched. Instead of using passing all entity identifiers, Hibernate simply reruns the previous query that fetched the Restaurant entities.

P.S. As for the FetchMode.JOIN option, please note that as it's mentioned here:

The reason why we are not using a JPQL query to fetch multiple Department entities is because the FetchMode.JOIN strategy would be overridden by the query fetching directive.

To fetch multiple relationships with a JPQL query, the JOIN FETCH directive must be used instead.

So, I guess the most flexible way for your case would be to write own JPQL query and use JOIN FETCH directive where it's needed.

  • Related