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