본문 바로가기
JAVA/JPA

인프런 JPA 서비스 최적화 방법 "김영한" -PlusUltraCode-

by PlusUltraCode 2024. 7. 25.
 

JPQL 경로 표현식 정리

JPQL(Java Persistence Query Language)은 객체 지향 쿼리 언어로, 엔티티 객체를 대상으로 쿼리를 작성할 수 있게 해줍니다. JPQL에서는 경로 표현식(Path Expression)을 사용하여 객체 그래프를 탐색할 수 있습니다. 이를 통해 엔티티 간의 연관 관계를 쉽게 조회할 수 있습니다. 경로 표현식에는 세 가지 종류가 있습니다:

1. 상태 필드 (State Field)

상태 필드는 단순히 값을 저장하기 위한 필드입니다. 예를 들어, m.username은 Member 엔티티의 username 필드에 접근하는 경로 표현식입니다. 상태 필드에서는 더 이상의 경로 탐색이 불가능합니다.

 
SELECT m.username FROM Member m

2. 단일 값 연관 필드 (Single-valued Association Field)

단일 값 연관 필드는 다른 엔티티를 참조하는 필드입니다. 예를 들어, m.team은 Member 엔티티와 연관된 Team 엔티티를 참조합니다. 이 경우 묵시적 내부 조인이 발생하며, 추가적인 탐색이 가능합니다. 그러나 묵시적 내부 조인은 예기치 않은 결과를 초래할 수 있으므로 주의가 필요합니다.

 
SELECT m FROM Member m JOIN m.team t

3. 컬렉션 값 연관 필드 (Collection-valued Association Field)

컬렉션 값 연관 필드는 다른 엔티티의 컬렉션을 참조합니다. 예를 들어, t.members는 Team 엔티티와 연관된 Member 엔티티의 컬렉션을 참조합니다. 이 경우에도 묵시적 내부 조인이 발생합니다.

 
SELECT m.username FROM Team t JOIN t.members m

묵시적 조인 피하기

묵시적 조인은 예상치 못한 결과를 초래할 수 있으므로, 명시적 조인을 사용하여 쿼리를 작성하는 것이 좋습니다. 명시적 조인은 쿼리의 의도를 명확하게 표현할 수 있습니다.

 
SELECT m.username FROM Member m JOIN m.team t

페치 조인 (Fetch Join)

페치 조인은 JPQL에서 성능 최적화를 위해 제공하는 기능으로, 데이터베이스에는 존재하지 않는 개념입니다. 주로 N+1 문제를 해결하기 위해 사용됩니다.

N+1 문제

일반적으로 아래와 같은 쿼리를 실행하면 연관된 엔티티는 프록시 객체로 조회됩니다.

 
SELECT m FROM Member m

프록시 객체의 실제 데이터는 나중에 접근할 때 추가적인 쿼리가 발생합니다. 이로 인해 N+1 문제가 발생합니다.

페치 조인을 사용한 N+1 문제 해결

페치 조인을 사용하면 연관된 엔티티를 한 번의 쿼리로 함께 조회할 수 있습니다. 이는 즉시 로딩과 유사하게 작동합니다.

 
SELECT m FROM Member m JOIN FETCH m.team

대부분의 N+1 문제는 페치 조인을 통해 해결할 수 있습니다.

OSIV와 성능 최적화

OSIV(Open Session In View) 또는 OEIV(Open EntityManager In View)는 영속성 컨텍스트의 생존 범위를 제어하는 설정입니다.

기본 설정 (OSIV 활성화)

spring.jpa.open-in-view의 기본값은 true입니다. 이는 영속성 컨텍스트가 API의 시작부터 끝까지 유지됨을 의미하며, 이로 인해 지연 로딩이 가능합니다. 그러나 실시간 트래픽이 중요한 환경에서는 커넥션이 부족할 수 있습니다.

properties
 
spring.jpa.open-in-view=true

OSIV 비활성화

OSIV를 비활성화하면 모든 지연 로딩을 트랜잭션 내에서 처리해야 합니다. 따라서 많은 지연 로딩 코드를 트랜잭션 내로 이동시켜야 하며, View Template에서 지연 로딩이 작동하지 않습니다.

properties
 
spring.jpa.open-in-view=false

OSIV 비활성화의 장점

고객 서비스와 같이 실시간 API에서는 OSIV를 비활성화하여 커넥션 리소스를 최적화할 수 있습니다. 반면, ADMIN과 같이 커넥션을 많이 사용하지 않는 곳에서는 OSIV를 활성화할 수 있습니다.

요약

  • 상태 필드: 단순 값 저장, 경로 탐색 불가능
  • 단일 값 연관 필드: 묵시적 내부 조인 발생, 추가 탐색 가능
  • 컬렉션 값 연관 필드: 묵시적 내부 조인 발생
  • 묵시적 조인 피하기: 명시적 조인을 사용
  • 페치 조인: N+1 문제 해결을 위한 성능 최적화
  • OSIV: 영속성 컨텍스트 생존 범위 제어, 실시간 트래픽 환경에서의 최적화

이러한 JPQL 경로 표현식과 성능 최적화 기법을 통해 효율적인 데이터 조회와 애플리케이션 성능을 향상시킬 수 있습니다.