(JPA) JPA 성능개선이란? 성능개선 목록 (N+1문제/read-only/Non-Transactional..)
JPA 성능개선 목록
1. N+1 문제 개선
JPA 사용시 성능상 가장 조심해야하는 것이 N+1 문제이다.
N+1 문제는 연관관계 설정이 되어있는 Entity 조회시 연관된 다른 Entity를 가져오기 위해
조회한 수 만큼 다시 SQL문이 수행되는 문제를 뜻한다.
예시)
: select 문이 여러번 사용되는 것이 보이시나요?
위 쿼리는 한 Entity를 조회했는데 연관된 Entity들을 가져오려고 생성되는 쿼리들 입니다. 성능이 많이 느렸습니다
- 해결방법
a. (fetch = FetchType.EAGER) :FetchType을 EAGER 로 변경 (즉시 로딩 전략)
: Entity 조회시점에 Mapping된 Entity를 join 문으로 함께 가져온다
b. JPQL fetch join 사용 (JPQL의 경우 a 방법으로 해결되지 않음)
: JPQL은 페치전략을 확인하지 않고 SQL문을 생성하기 때문에 FetchType을 EAGER로 변경해도
N+1 문제가 해결되지 않음. fetch join을 사용하여 join문으로 Mapping된 Entity를 가져오도록 해야한다
c. @BatchSize 사용
: Mapping된 Entity를 지정한 size 만큼 SQL의 IN 절을 사용해서 가져온다.
(위 사진예시의 select 여러번이 in 절에 묶여 실행되는 SQL문 수가 감소하겠죠?)
d. @Fetch(FetchMode.SUBSELECT) 사용
: Mapping된 Entity를 SQL의 IN 절을 사용해서 가져온다.
* 일반적으로 a, b 를 사용하여 N+1 문제를 해결
2. 읽기 전용 쿼리사용
Entity가 영속성 컨텍스트에 의해 관리되면 얻을 수 있는 이점 (1차캐시, 변경감지, 지연로딩 등) 도 많지만,
성능을 감소시킬 수 있다는 단점도 있다( 스냅샷 저장, 변경감지 수행 등)
* 메모리를 과도하게 사용하여서 로직 수행시 가비지 컬렉터가 함께 동작하여
성능이 급격하게 느려지는 현상이 있다 (경험담입니다.. Entity 백개 정도 넘어가니 급격히 느려졌습니다)
따라서 Entity를 조회만 하는 경우이고, 다시 조회 하는 경우도 적다면 읽기 전용으로 사용하여 메모리 사용을 최적화 할수 있다.
- 읽기 전용쿼리 사용방법
a. 스칼라 타입으로 조회
: select o.id, o.name, o.price from Order o
위처럼 스칼라 타입으로 조회하면 객체가 영속성 컨텍스트에 의해 관리되지 않는다.
b. 읽기 전용 트랜잭션 사용
: @Transactional(readOnly=true)
하이버네이트 세션 플러시 모드가 MANUAL로 설정되어 트랜잭션 커밋시 자동으로 flush가 호출되지 않는다.
(flush가 호출되지 않으니 스냅샷 비교등 무거운로직을 수행하지 않는다)
c. 읽기 전용 쿼리 힌트 사용
: query hint를 readOnly=true로 설정
Entity를 읽기 전용으로 설정하여 스냅샷 보관하지 않음
d. 트랜잭션 밖에서 읽기
: @Transactional(propagation = Propagation.NOT_SUPPORTED)
메소드 수행시 트랜잭션을 생성하지 않도록 한다.
트랜잭션 자체가 없으므로 트랜잭션 커밋시 flush가 호출되지 않는다.
다음 포스트에는 JPA 성능개선을 적용한 과정을 포스팅 하겠습니다.
읽어주셔서 감사합니다~
By. RyanKim
JPA 성능개선 적용:
https://lion-king.tistory.com/entry/JPA-Performance-Improvement