0
0
Spring Bootframework~5 mins

N+1 query problem in Spring Boot

Choose your learning style9 modes available
Introduction

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.

When loading a list of items and their related details from a database.
When you see your app making many small database calls instead of one big call.
When you want to improve app speed by reducing database queries.
When using ORM tools like JPA or Hibernate to fetch related entities.
When debugging slow page loads caused by database access.
Syntax
Spring Boot
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.

Examples
This example shows fetching orders, then for each order fetching its customer separately, causing N+1 queries.
Spring Boot
List<Order> orders = orderRepository.findAll();
for (Order order : orders) {
    Customer customer = order.getCustomer();
    System.out.println(customer.getName());
}
This example uses a JOIN FETCH query to get orders and customers in one query, avoiding N+1 problem.
Spring Boot
@Query("SELECT o FROM Order o JOIN FETCH o.customer")
List<Order> findAllWithCustomers();
Sample Program

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.

Spring Boot
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());
        }
    }
}
OutputSuccess
Important Notes

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.

Summary

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.