Spring/그 외

[Spring] 스프링 성능 최적화에 대한 고찰

ummchicken 2023. 1. 24. 19:57

어느날 문득 

무작정 스프링을 쓰는 것보단, 

왜 쓰는지에 대해 생각을 해보면서 코딩을 하면 좋을 것 같다는 생각이 들었다.

 

 

 

난 실무를 경험한 적이 없으므로, 

실무를 하며 "아 이렇게 해야겠구나"라는 체감을 한 적이 없다.

그래서 어쩔 수 없이 아쉽지만 이론상으로라도 접해야겠다.

(그냥 아무 생각 없이 하는 것보단 나을 것 같음)

 

 

 

제일 먼저 찾아본 자료는 

[REST API를 개발할 때, 성능 최적화를 하는 방법들]에 대해서다.

 

 

제일 중요한 건 엔티티를 웹에 노출해서는 안 된다고 한다.

 

 

그럼 어떻게 해야 할까?

→ 간단하다. 별도의 DTO를 만들어, 거기서 조회한 엔티티를 넣어서 반환해주면 된다.

 

 

 

 

문제점

JPA로 애플리케이션을 개발할 때 발생하는 다양한 성능 문제와 해결 방안을 알아보자.

 

N + 1 문제

JPA로 애플리케이션을 개발할 때 성능상 가장 주의해야 하는 것이 N + 1 문제다.
처음 실행한 SQL의 결과 수만큼 추가로 SQL을 실행하는 것을 N + 1 문제라 한다.

즉시 로딩은 JPQL을 실행할 때 N + 1 문제가 발생할 수 있다.

 

 

지연 로딩과 N + 1

즉시 로딩 시나리오를 지연 로딩(fetch = FetchType.LAZY)으로 변경해도 N + 1 문제에서 자유로울 순 없다.

 

 

 

이처럼 N + 1 문제는 즉시 로딩과 지연 로딩일 때 모두 발생할 수 있다.

 

 


 

조회 API의 성능 최적화를 위해

N + 1 문제를 피할 수 있는 다양한 방법을 알아보자.

 

 

1. 페치 조인 (fetch join)을 사용해라

N + 1 문제를 해결하는 가장 일반적인 방법은 페치 조인을 사용하는 것이다.
페치 조인은 SQL 조인을 사용해서 연관된 엔티티를 함께 조회하므로,
N + 1 문제가 발생하지 않는다.

 

 

2. 엔티티를 웹에 노출해서는 안된다.

 

 

3. 연관 관계일 때, 한 곳을 @JsonIgnore 처리해야 한다. (엔티티를 직접 노출할 때)

 

 

4. 읽기 전용 쿼리의 성능 최적화

읽기 전용 트랜잭션 사용
@Transactional(readOnly = true)

→ 이렇게 하면 강제로 플러시를 호출하지 않는 한 플러시가 일어나지 않는다.

따라서 트랜잭션을 커밋해도 영속성 컨텍스트를 플러시하지 않는다.

영속성 컨텍스트를 플러시하지 않으니

엔티티의 등록, 수정, 삭제는 당연히 동작하지 않는다.

 

 

 


 

쿼리 방식 선택 권장 순서

  1. 우선 엔티티를 DTO로 변환하는 방법을 선택한다.
  2. 필요하면 페치 조인으로 성능을 최적화 한다. 대부분의 성능 이슈가 해결된다.
  3. 그래도 안 되면, DTO로 직접 조회하는 방법을 사용한다.
  4. 최후의 방법은 JPA가 제공하는 네이티브 SQL이나, 스프링 JDBC Template을 사용해서 SQL을 직접 사용한다.

 

자세한 건 여기에 적어놓았다.

 

 

 

 


출처