I have a entity class which has multiple children with oneToMany
association:
public class A{
private Long id;
private String name;
@OneToMany(mappedBy = "A", fetch = FetchType.LAZY, cascade = CascadeType.ALL,
orphanRemoval = true)
private List<B>bList= new ArrayList<>();
@OneToMany(mappedBy = "A", fetch = FetchType.LAZY, cascade = CascadeType.ALL,
orphanRemoval = true)
private List<C>cList= new ArrayList<>();
@OneToMany(mappedBy = "A", fetch = FetchType.LAZY, cascade = CascadeType.ALL,
orphanRemoval = true)
private List<D>dList= new ArrayList<>();
//getters and setters
}
For B,C and D I have set ManyToOne
. In a word, they are in a bi-directional relationship.
Now, If I fetch A by id, I see a lot of queries get fired which turns out to be N+1
problem. To solve this, I added @Fetch(FetchMode.SUBSELECT)
to all of the oneToMany
relationships above which cause less queries to be fired.
My question is:
is it okay using @Fetch(FetchMode.SUBSELECT)
or I can optimize it further?
what if I want to fetch all "As" by calling findAll() method? What should be the syntax for multiple children? Like
"select a from A a join fetch a.b then ??"
List< A > findAll()
Now, If I fetch A by id, I see a lot of queries get fired which turns out to be N+1 problem. To solve this, I added @Fetch(FetchMode.SUBSELECT) to all of the oneToMany relationships above which cause less queries to be fired.
You are not saying how/when these queries are fired, so a possible reason for the problem is that you are returning entities from your HTTP endpoints which are then serialized. Using @Fetch(FetchMode.SUBSELECT)
is one way to "improve" the performance but will only work nicely if the base query which you use to fetch A
is simple. If it gets too complex (pagination, complex predicates, etc.) you should stick to the default which is SELECT
and instead configure a proper batch size via the @BatchSize( size = 32 )
annotation. A good value for the batch size would be the amount of A
instances that you expect to be returned such that only a single query is executed per collection. If you allow a max page size of e.g. 50, you setting the value to 50 would be perfect.
List< A > findAll()
Do not ever do this if you care about performance and usability. It rarely makes sense to allow returning all elements, as no user can handle more than ~20 elements at a time anyway. As mentioned before, always have some kind of upper limit on the page size to prevent misuses that can cause performance issues.