Ответ
Проблема N+1 — это антипаттерн производительности в ORM, когда для загрузки одной сущности и связанной с ней коллекции из N элементов выполняется 1 запрос для родителя и N отдельных запросов для каждого элемента коллекции.
Проблемный пример (Lazy Loading):
@Entity
public class Author {
@Id
private Long id;
private String name;
@OneToMany(mappedBy = "author", fetch = FetchType.LAZY) // Ленивая загрузка по умолчанию
private List<Book> books;
}
// В сервисе или DAO:
List<Author> authors = entityManager.createQuery("SELECT a FROM Author a", Author.class)
.getResultList(); // 1-й запрос: получаем всех авторов
for (Author a : authors) {
// Для каждого автора здесь выполняется отдельный запрос к БД для загрузки books!
System.out.println(a.getBooks().size()); // N запросов
}
// ИТОГО: 1 + N запросов
Основные решения:
- Использовать
JOIN FETCHв JPQL/HQL:List<Author> authors = entityManager.createQuery( "SELECT DISTINCT a FROM Author a LEFT JOIN FETCH a.books", Author.class) .getResultList(); // ВСЕ данные загружаются ОДНИМ запросом - Использовать
@EntityGraph:@EntityGraph(attributePaths = {"books"}) @Query("SELECT a FROM Author a") List<Author> findAllWithBooks(); - Настроить
@BatchSizeдля ленивой загрузки:@OneToMany(mappedBy = "author") @BatchSize(size = 10) private List<Book> books; // Hibernate загрузит книги для авторов пачками (например, по 10), уменьшив N+1 до N/10 + 1Выбор стратегии зависит от конкретного сценария использования данных.