✅ Use JOIN FETCH
when:
- You always need the associated data in that query’s result (e.g., displaying authors and their books in a UI table).
- You’re only fetching one collection or single-valued associations → avoids Cartesian explosion.
- You want maximum performance with one query.
🚨 Avoid if:
- You need to join multiple collections → can produce huge result sets with duplicated parent rows.
✅ Use EntityGraph
when:
- You want to control fetching dynamically at runtime (e.g., REST APIs where some endpoints need extra data, others don’t).
- You prefer not to hardcode
JOIN FETCH
into your JPQL queries. - You’re using JPA 2.1 or newer.
🚨 Avoid if:
- You need precise control over query shape beyond what
EntityGraph
allows.
✅ Use Batch fetching
(@BatchSize
) when:
- You want to keep lazy loading but reduce N+1 overhead.
- You load a list of parents (e.g., orders) and then later access child associations (e.g., order items).
- Your use case includes paging or processing batches of entities.
🚨 Avoid if:
- Your data access pattern doesn’t touch multiple proxies together → batching can’t kick in.
✅ Use Subselect fetching
when:
- You load a list of parent entities in one query, and later need their collections.
- You want to avoid both N+1 and Cartesian product issues with
JOIN FETCH
. - Your expected parent list size is moderate (tens to low hundreds) → avoids massive
IN
clauses.
🚨 Avoid if:
- Your parent list can be huge → subselect’s
IN (...)
clause could become inefficient or exceed database limits.
✅ Use EAGER
fetching when:
- The association is always needed, for example, small one-to-one relationships like
User.profile
. - You control entity usage tightly and know loading the association by default is safe.
🚨 Avoid if:
- The association is a collection or large data → eager fetching can load too much data or cause performance bottlenecks.
✅ Use manual queries with WHERE IN (...)
when:
- You want precise, explicit control over fetching behavior in your service layer.
- You have a complex access pattern not easily expressed with
JOIN FETCH
or EntityGraphs.
🔥 Quick cheatsheet:
Scenario | Best strategy |
---|---|
Need associated data every time | JOIN FETCH |
Varying needs for associated data | EntityGraph |
Keep lazy loading but reduce N+1 overhead | Batch fetching |
Loading a page of parents + their children | Subselect fetching |
One-to-one/small always-needed data | EAGER fetching |
Special or complex needs | Manual queries |