Understand the different Hibernate / JPA behavior for findAll and findOne

I was debugging a performance issue using the findAll method (from the JPA Spring Data Repository) and the problem was using the fetch plan that was used. (Hibernate did additional Selects to fetch additional objects instead of using a fetch connection)

My object has some relationship with other objects and the problem I am facing is with * ToOne relationships.

After spending some time on google, I realized that there are ways to manage queries that Hibernate will execute (using JPA criteria, NamedEntityGraph, custom queries, ...).

I have created a small example demonstrating different types of behavior, but I would like to understand why Hibernate does this by default . I've spent some time searching through the docs, but I couldn't find a link to this default behavior.

https://github.com/pmvilaca/jpa-test

Difference:

Hibernate: 
SELECT
  user0_.id                 AS id1_1_0_,
  userdetail1_.id           AS id1_21_,
  contactdet2_.id           AS id1_0_2_,
  user0_.contact_details_id AS contact_3_1_0_,
  user0_.name               AS name2_1_0_,
  userdetail1_.nationality  AS national2_2_1_,
  userdetail1_.user_id      AS user_id3_2_1_,
  contactdet2_.email        AS email2_0_2_,
  contactdet2_.mobile       AS mobile3_0_2_
FROM user user0_
  LEFT OUTER JOIN user_details userdetail1_ ON user0_.id = userdetail1_.user_id
  LEFT OUTER JOIN contact_details contactdet2_ ON user0_.contact_details_id = contactdet2_.id

      

and

Hibernate: select user0_.id as id1_1_, user0_.contact_details_id as contact_3_1_, user0_.name as name2_1_ from user user0_
Hibernate: select contactdet0_.id as id1_0_0_, contactdet0_.email as email2_0_0_, contactdet0_.mobile as mobile3_0_0_ from contact_details contactdet0_ where contactdet0_.id=?
Hibernate: select userdetail0_.id as id1_2_2_, userdetail0_.nationality as national2_2_2_, userdetail0_.user_id as user_id3_2_2_, user1_.id as id1_1_0_, user1_.contact_details_id as contact_3_1_0_, user1_.name as name2_1_0_, contactdet2_.id as id1_0_1_, contactdet2_.email as email2_0_1_, contactdet2_.mobile as mobile3_0_1_ from user_details userdetail0_ left outer join user user1_ on userdetail0_.user_id=user1_.id left outer join contact_details contactdet2_ on user1_.contact_details_id=contactdet2_.id where userdetail0_.user_id=?
Hibernate: select contactdet0_.id as id1_0_0_, contactdet0_.email as email2_0_0_, contactdet0_.mobile as mobile3_0_0_ from contact_details contactdet0_ where contactdet0_.id=?
Hibernate: select userdetail0_.id as id1_2_2_, userdetail0_.nationality as national2_2_2_, userdetail0_.user_id as user_id3_2_2_, user1_.id as id1_1_0_, user1_.contact_details_id as contact_3_1_0_, user1_.name as name2_1_0_, contactdet2_.id as id1_0_1_, contactdet2_.email as email2_0_1_, contactdet2_.mobile as mobile3_0_1_ from user_details userdetail0_ left outer join user user1_ on userdetail0_.user_id=user1_.id left outer join contact_details contactdet2_ on user1_.contact_details_id=contactdet2_.id where userdetail0_.user_id=?
Hibernate: select userdetail0_.id as id1_2_2_, userdetail0_.nationality as national2_2_2_, userdetail0_.user_id as user_id3_2_2_, user1_.id as id1_1_0_, user1_.contact_details_id as contact_3_1_0_, user1_.name as name2_1_0_, contactdet2_.id as id1_0_1_, contactdet2_.email as email2_0_1_, contactdet2_.mobile as mobile3_0_1_ from user_details userdetail0_ left outer join user user1_ on userdetail0_.user_id=user1_.id left outer join contact_details contactdet2_ on user1_.contact_details_id=contactdet2_.id where userdetail0_.user_id=?

      

Any idea?

thank

+3


source to share


1 answer


The default fetch type for @OneToOne

: FetchType.EAGER . Therefore, without any hint of query optimization, Hibernate will perform the following steps:

Select all User

's:

Hibernate: 
select
    user0_.id as id1_1_,
    user0_.contact_details_id as contact_3_1_,
    user0_.name as name2_1_ 
from
    user user0_

      



Now eagerly download each User

ContactDetails

andUserDetails

Hibernate: 
select
    contactdet0_.id as id1_0_0_,
    contactdet0_.email as email2_0_0_,
    contactdet0_.mobile as mobile3_0_0_ 
from
    contact_details contactdet0_ 
where
    contactdet0_.id=?
Hibernate: 
select
    userdetail0_.id as id1_2_2_,
    userdetail0_.nationality as national2_2_2_,
    userdetail0_.user_id as user_id3_2_2_,
    user1_.id as id1_1_0_,
    user1_.contact_details_id as contact_3_1_0_,
    user1_.name as name2_1_0_,
    contactdet2_.id as id1_0_1_,
    contactdet2_.email as email2_0_1_,
    contactdet2_.mobile as mobile3_0_1_ 
from
    user_details userdetail0_ 
left outer join
    user user1_ 
        on userdetail0_.user_id=user1_.id 
left outer join
    contact_details contactdet2_ 
        on user1_.contact_details_id=contactdet2_.id 
where
    userdetail0_.user_id=?

...

      

This is commonly referred to as a problem n + 1

. See here .

+1


source







All Articles