N+1 query problem trong JPA/Hibernate và cách khắc phục
22/07/2026
N+1 là vấn đề hiệu năng phổ biến nhất khi dùng ORM. Nó âm thầm biến một trang danh sách thành hàng trăm câu truy vấn database mà bạn không nhận ra cho tới khi production chậm.
N+1 xảy ra thế nào?
Bạn load N đơn hàng (1 query). Với mỗi đơn, khi truy cập order.getCustomer() được cấu hình lazy, Hibernate bắn thêm 1 query để lấy customer. Tổng cộng: 1 + N query.
List<Order> orders = repo.findAll(); // 1 query
for (Order o : orders) {
System.out.println(o.getCustomer().getName()); // +1 query mỗi vòng
}
Cách phát hiện
- Bật
spring.jpa.show-sql=truevàhibernate.format_sqlđể thấy query thật - Dùng công cụ như Hibernate statistics hoặc datasource-proxy đếm số query mỗi request
Ba cách sửa
- JOIN FETCH trong JPQL:
SELECT o FROM Order o JOIN FETCH o.customer— lấy tất cả trong 1 query - Entity Graph: khai báo
@EntityGraphtrên repository method để nạp sẵn quan hệ - Batch fetching:
@BatchSize(size = 50)gom N query lẻ thành vài query IN(...)
Cẩn thận: đừng để mọi quan hệ thành EAGER để tránh N+1 — sẽ nạp thừa dữ liệu. Giữ LAZY làm mặc định và nạp có chủ đích theo từng use case.
👉 Dùng thử công cụ liên quan trên dev-hub: JSON Formatter — chạy hoàn toàn trong trình duyệt, không gửi dữ liệu lên server.