보라코딩

JPA N+1 문제 본문

코딩/Spring

JPA N+1 문제

new 보라 2024. 6. 24. 19:57
Lazy 로딩을 사용할 때 N+1 문제가 발생하지 않는 이유

 

 

Lazy Loading (지연 로딩) 동작 원리

  1. 지연 로딩 설정: JPA에서는 연관 관계를 지연 로딩으로 설정할 수 있습니다. 이는 연관된 엔티티를 실제로 사용할 때까지 데이터베이스에서 가져오지 않고, 필요할 때 로딩하는 방식입니다.
  2. Proxy 객체 생성: Lazy 로딩이 설정된 연관 관계는 실제 엔티티 대신 프록시(proxy) 객체를 반환합니다. 프록시 객체는 실제 엔티티를 대신하여 필요한 시점에 데이터베이스에서 엔티티를 로딩하는 역할을 합니다.
  3. 첫 번째 쿼리 실행: 예를 들어, 부모 엔티티를 조회할 때 연관된 자식 엔티티는 초기에 로딩되지 않고, 대신에 해당 자식 엔티티들에 대한 데이터베이스 쿼리가 발생하지 않습니다. 대신, 부모 엔티티의 필드에는 자식 엔티티에 대한 참조(프록시)가 설정됩니다.
  4. 자식 엔티티 접근 시 로딩: 실제로 자식 엔티티를 사용하려 할 때(예: 자식 엔티티의 필드를 조회하거나 메서드를 호출할 때), 프록시 객체는 데이터베이스에 추가 쿼리를 실행하여 실제 자식 엔티티를 로딩합니다. 이때 N+1 문제가 발생하지 않도록 자식 엔티티들을 한 번에 모아서 로딩할 수 있습니다.

N+1 문제 예제

  1. 부모 엔티티 목록 조회: 예를 들어, 부모 엔티티가 10개 있다고 가정합니다.
  2. N+1 쿼리 문제: Lazy 로딩을 사용하지 않고, 부모 엔티티 목록을 조회한 후 각 부모 엔티티마다 연관된 자식 엔티티를 추가로 조회하려고 할 때, 각 부모 엔티티마다 데이터베이스 쿼리가 추가로 발생합니다. 따라서 부모 엔티티 조회 1번 + 자식 엔티티 조회 N번으로 총 N+1 개의 쿼리가 발생하게 됩니다.

Lazy 로딩 사용 시 N+1 문제 해결

  • 초기 조회 시점: Lazy 로딩을 사용하면 처음에는 연관된 자식 엔티티들을 모두 로딩하지 않고, 프록시 객체를 부모 엔티티에 설정합니다. 이로 인해 처음에는 추가적인 쿼리가 발생하지 않습니다.
  • 실제 사용 시점: 부모 엔티티에서 실제로 자식 엔티티의 필드나 메서드에 접근할 때, JPA는 프록시 객체를 통해 실제 데이터베이스 쿼리를 실행하여 필요한 자식 엔티티를 로딩합니다. 이때 자식 엔티티들을 한 번에 모아서 로딩할 수 있어 N+1 문제를 방지할 수 있습니다.

결론

Lazy 로딩을 사용하면 연관된 엔티티를 초기에 모두 로딩하지 않고, 필요할 때 데이터베이스에서 추가 쿼리를 실행하여 로딩합니다. 이 방식은 N+1 문제를 피할 수 있는 주요 전략 중 하나입니다. 따라서 애플리케이션에서 성능 최적화를 위해 JPA 엔티티 관계를 설계할 때 Lazy 로딩을 적절히 활용하는 것이 중요합니다.