🔎 What is the N+1 select problem?
It happens when you fetch a collection of parent entities, and then Hibernate lazily loads each child entity in a separate query.
Specifically:
1️⃣ First, Hibernate executes 1 query to load your list of N parent entities.
2️⃣ Then, for each of those N parents, it issues 1 additional query to load the associated child entities.
So in total, you get 1 + N queries, which can be disastrous for performance if N is large.
📌 Example
Say you have Author
entities, each with a collection of Book
entities:
List<Author> authors = session.createQuery("FROM Author", Author.class).getResultList();
Hibernate first runs:
SELECT * FROM authors; -- 1 query
Then, for each author, it does:
SELECT * FROM books WHERE author_id = ?; -- N queries
So fetching 100 authors would result in 101 queries, which is inefficient and can slow your app significantly.
✅ How to solve it?
Use fetch join to load both parents and their children in a single query:
List<Author> authors = session.createQuery(
"SELECT DISTINCT a FROM Author a JOIN FETCH a.books", Author.class
).getResultList();
This translates into:
SELECT a.*, b.* FROM authors a
JOIN books b ON a.id = b.author_id;
So you get 1 query instead of N+1, which greatly improves performance.
📝 Key points
✔ The problem stems from lazy loading of collections without batching or fetch joins.
✔ It’s called “N+1” because it literally does 1 query for the main list + N more queries for details.
✔ Solving it usually involves fetch joins, adjusting fetch strategies, or using batch fetching.