Search code examples
javahibernateormlazy-loadingeager-loading

Retrieve relationships via LAZY loading or JOIN FETCH?


Assume I have the following entity:

@Entity
public class Foo {
  @Id
  @GeneratedValue(strategy = IDENTITY)
  private Long id;

  @ManyToOne(fetch = LAZY)
  private EntityA a;

  @ManyToOne(fetch = LAZY)
  private EntityB b;

  .
  .
  .


  @ManyToOne(fetch = LAZY)
  private EntityX x;
}

All relationships are lazy loaded because in majority of cases they're not needed for business logic. Next, assume there's an endpoint that returns all data for a specific Foo entity by ID. There're two options to retrieve data:

  1. Rely on lazy loading which means that X database requests will be made for X relationships. This approach seems fine considering that requests are lightweight and they fetch only 1 row per table. Additionally, its more pleasant for code maintenance.

  2. Write a big HQL query that JOIN FETCHes all necessary relationships. This approach performs only one database request and works by a few milliseconds faster than the option above, however, hibernate generates a very big SQL that might have performance issues in specific edge cases and the developer has to maintain a big HQL query.

Are there any best practices around this case? Which approach would be better for this specific scenario?


Solution

  • however, hibernate generates a very big SQL that might have performance issues in specific edge cases

    I don't quite understand. The word "might" seems to be doing a whole lotta work here. Do you have any actual evidence that the SQL Hibernate generates results in poor performance?

    Because in general, joining multiple @ManyToOne associations is something that the database is able to do very efficiently, and is unlikely to cause a problem.

    And to be clear "a very big SQL" is not in any way an indicator of poor performance.

    Therefore: your option 2 is the recommendation.

    Now, on the other hand, problems do arise if you join multiple @OneToMany associations, and so for that case one might need to consider more exotic solutions, for example, the use of FetchMode.SUBSELECT. But that is not the case you have exhibited in the code above.