JPA N + 1 문제에 대하여
JPA를 사용하다보면 다양한 문제를 마주치곤 하는데요.
오늘은 그 중 가장 대표적인 문제인 N + 1 문제에 대해 알아보고자 합니다.
개요
JpaRepository를 통해 엔티티 리스트를 조회하니 리스트에 존재하는 Entity의 갯수만큼 연관되어 있는 Entity에 대한 조회 쿼리가 수행되는 모습을 볼 수 있었습니다.
@Entity
@Getter
@Table(name = "products")
@NoArgsConstructor(access = AccessLevel.PROTECTED)
public class Product {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@Column(nullable = false)
private String name;
@Column(nullable = false)
private long price;
@Getter(AccessLevel.NONE)
@Embedded
private ProductImages productImages;
@OneToMany(fetch = FetchType.EAGER, mappedBy = "product")
private List<Review> reviews;
...
}
@Entity
@Getter
@NoArgsConstructor(access = AccessLevel.PROTECTED)
public class Review {
@Id
private Long id;
@Column(name = "user_id")
private String reviewer;
private String content;
@ManyToOne
private Product product;
...
}
public interface ProductRepository extends JpaRepository<Product, Long> {
}
@SpringBootTest
class ProductRepositoryTest {
@Autowired
ProductRepository productRepository;
@Test
void N_1_문제_테스트() {
// given
Product product_1 = Product.of("product_1", 30000, asList(ProductImage.of("imagePath", 0)));
Product product_2 = Product.of("product_2", 20000, asList(ProductImage.of("imagePath", 0)));
productRepository.save(product_1);
productRepository.save(product_2);
// when
productRepository.findAll();
}
}
우선 예상과는 다르게 Join 쿼리가 수행되지 않고 Product 쿼리와 Review 쿼리가 각각 따로 수행되는 모습을 볼 수 있는데,
여기서 더 이상한 점은 Product의 수만큼 Review 쿼리가 수행된 것을 볼 수 있습니다.
Why ?
왜 이러한 문제가 발생하는 것일까요 ?
우선 문제는 아래의 코드에 있습니다.
...
public class Product {
...
@OneToMany(fetch = FetchType.EAGER, mappedBy = "product")
private List<Review> reviews;
...
}
이 부분을 보시면 현재 로딩 전략이 EAGER 로딩으로 되어있는데요.
JPA의 글로벌 Fetch 전략은 단일 Entity를 조회할 경우에만 즉시 적용이 되지만,
Entity 리스트 조회시 즉시 적용이 되지 않고, Entity 리스트를 PersistContext에 올린 후
적용됩니다.
그렇기 때문에 Entity 리스트가 PersistContext에 모두 올라간 후, EAGER fetch 전략임을 확인하여
Entity 리스트 조회후 Entity 리스트에 존재하는 Entity들의 연관된 Entity를 조회하게 됩니다.
그래서 결과적으로 N + 1 문제가 발생하게 됩니다.
Resolve
Fetch join 사용
- JPA Query Method 사용시
- Querydsl 사용시
Fetch join 사용시 페이징 쿼리가 수행되지 않음
@EntityGraph 어노테이션 사용
@BatchSize 어노테이션 사용
Author And Source
이 문제에 관하여(JPA N + 1 문제에 대하여), 우리는 이곳에서 더 많은 자료를 발견하고 링크를 클릭하여 보았다 https://velog.io/@wodyd202/JPA-N-1-문제에-대하여저자 귀속: 원작자 정보가 원작자 URL에 포함되어 있으며 저작권은 원작자 소유입니다.
우수한 개발자 콘텐츠 발견에 전념 (Collection and Share based on the CC Protocol.)