The N+1 query problem happens when your app asks the database too many times for related data. This slows down your app and wastes resources.
N+1 query problem in Spring Boot
Start learning this pattern below
Jump into concepts and practice - no test required
List<Entity> entities = repository.findAll();
for (Entity e : entities) {
Related related = e.getRelated(); // triggers extra query per entity
}This code fetches all entities first, then for each entity fetches related data separately.
Each call to getRelated() can cause a new database query, leading to many queries.
List<Order> orders = orderRepository.findAll();
for (Order order : orders) {
Customer customer = order.getCustomer();
System.out.println(customer.getName());
}@Query("SELECT o FROM Order o JOIN FETCH o.customer")
List<Order> findAllWithCustomers();This Spring Boot example shows how to avoid the N+1 query problem by using a JOIN FETCH query. It loads orders and their customers in one database call, then prints customer names.
import org.springframework.data.jpa.repository.JpaRepository; import org.springframework.data.jpa.repository.Query; import org.springframework.stereotype.Repository; import jakarta.persistence.*; import java.util.List; @Entity class Order { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) private Long id; @ManyToOne(fetch = FetchType.LAZY) private Customer customer; public Customer getCustomer() { return customer; } } @Entity class Customer { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) private Long id; private String name; public String getName() { return name; } } @Repository interface OrderRepository extends JpaRepository<Order, Long> { @Query("SELECT o FROM Order o JOIN FETCH o.customer") List<Order> findAllWithCustomers(); } public class NPlusOneDemo { private final OrderRepository orderRepository; public NPlusOneDemo(OrderRepository orderRepository) { this.orderRepository = orderRepository; } public void showOrders() { List<Order> orders = orderRepository.findAllWithCustomers(); for (Order order : orders) { System.out.println(order.getCustomer().getName()); } } }
Lazy loading causes the N+1 problem because related data loads only when accessed.
Using JOIN FETCH or entity graphs helps load related data eagerly in one query.
Check your SQL logs or use a profiler to spot N+1 queries in your app.
The N+1 query problem happens when your app makes one query for a list, then one query per item for related data.
This slows down your app and wastes database resources.
Use JOIN FETCH or similar techniques to load related data in one query and avoid this problem.
Practice
N+1 query problem in Spring Boot applications?Solution
Step 1: Understand the query pattern
The N+1 problem occurs when the app first fetches a list (1 query), then fetches related data for each item separately (N queries).Step 2: Identify the problem impact
This causes many queries, slowing down the app and wasting resources.Final Answer:
Making one query to fetch a list, then one query per item to fetch related data -> Option DQuick Check:
N+1 query problem = multiple queries instead of one [OK]
- Thinking N+1 means only one query is made
- Confusing it with syntax errors
- Assuming it is about missing queries
JOIN FETCH in a Spring Data JPA query to avoid the N+1 problem?Solution
Step 1: Understand JOIN FETCH usage
JOIN FETCH tells JPA to fetch related entities eagerly in one query, avoiding multiple queries.Step 2: Identify correct syntax
@Query("SELECT o FROM Order o JOIN FETCH o.items") uses JOIN FETCH correctly to fetch orders with their items in one query.Final Answer:
@Query("SELECT o FROM Order o JOIN FETCH o.items") -> Option AQuick Check:
JOIN FETCH = eager fetch to avoid N+1 [OK]
- Using JOIN without FETCH causes lazy loading
- Using WHERE instead of JOIN FETCH
- Missing FETCH keyword
@Query("SELECT c FROM Customer c")
List<Customer> findAllCustomers();And assuming
Customer has a lazy-loaded orders collection, what happens when you call findAllCustomers() and then access orders for each customer?Solution
Step 1: Analyze the query and lazy loading
The query fetches customers only; orders are lazy-loaded, so not fetched initially.Step 2: Accessing orders triggers queries
Accessing orders for each customer triggers one query per customer, causing N+1 queries total.Final Answer:
One query to get customers, then one query per customer to get orders (N+1 problem) -> Option AQuick Check:
Lazy loading causes N+1 queries [OK]
- Assuming all data loads in one query
- Thinking no queries run until orders accessed
- Confusing lazy and eager loading
List<Author> authors = authorRepository.findAll();
for (Author a : authors) {
System.out.println(a.getBooks().size());
}How can you fix it to avoid the N+1 problem?
Solution
Step 1: Identify cause of N+1
Calling getBooks() inside loop triggers one query per author due to lazy loading.Step 2: Use JOIN FETCH to load books eagerly
Changing repository query to use JOIN FETCH loads authors and books in one query, avoiding N+1.Final Answer:
Change repository method to use @Query("SELECT a FROM Author a JOIN FETCH a.books") -> Option CQuick Check:
JOIN FETCH fixes N+1 by eager loading [OK]
- Adding @Transactional does not fix N+1
- Using threads does not solve query count
- Removing loop hides problem but does not fix it
Post and Comment with a one-to-many lazy relationship. You want to fetch all posts with their comments efficiently. Which approach best avoids the N+1 problem and handles posts with no comments?Solution
Step 1: Understand lazy loading and N+1
Lazy loading comments causes one query per post when accessed, causing N+1 problem.Step 2: Use LEFT JOIN FETCH to include posts without comments
LEFT JOIN FETCH fetches posts and their comments in one query, including posts with no comments.Final Answer:
@Query("SELECT p FROM Post p LEFT JOIN FETCH p.comments") to fetch posts and comments in one query -> Option BQuick Check:
LEFT JOIN FETCH avoids N+1 and includes empty collections [OK]
- Using INNER JOIN FETCH excludes posts without comments
- Fetching comments separately causes N+1
- Ignoring comments loses needed data
