API 개발 (5) - OneToMany관계 정리

2021. 7. 30. 15:37·스프링/스프링부트 API 설계 정리

API를 통해서 원하는 엔티티(or DTO)를 조회하는 방법에 대해 알아보았다. 해당 내용들을 정리해보자.

 

1. 엔티티 조회

V1 - 엔티티 조회해서 그대로 반환

  • DTO를 통하지 않고 쿼리를 통해 반환 받은 목록을 그대로 반환했다.
  • 엔티티를 그대로 반환하므로 매우 안좋은 방법이다.
  • 순환조회를 막기위해 Entity에 @JsonIgnore를 넣어서 막아야 한다.
    • 따라서 Entity 수정이 필연적으로 발생된다.

 

V2 - 엔티티 조회해서 DTO로 변환 후 반환

  • Entity를 바로 반환하지 않게 변환했지만 객체 내 LAZY 객체에 대해 접근하면서 즉시 로딩이 되면서 N + 1문제가 발생했다.
  • 또한, LAZY 객체 내 1 : N 객체가 존재해서 1 + N번 쿼리 (LAZY 객체) + N번 쿼리 (Many 객체) + N * M번 쿼리 가 발생했다.
    • 1번 조회 -> 2개의 결과, 2번 lazy객체 2개를 각각 조회 4번조회 -> toMany객체를 2번 조회 -> toMany객체 내 2개의 객체를 2회 조회해서 총 4번 조회 -> 총 11회 쿼리 발생
  • 엄청난 쿼리 수의 증가 문제가 있다.

 

V3 - 조회시 FETCH JOIN을 사용해서 Query 생성

  • Entity에 대한 쿼리문을 작성해서 조회
  • OneToOne, ManyToOne, OneToMany에 해당하는 모든 LAZY 객체를 FETCH JOIN해서 가져온다. 이때 toMany로 인해서 DB 테이블이 Many객체 기준으로 바뀌면서 Row수가 증가한다.
    이 결과값을 그대로 반환하면 중복된 객체를 가진 데이터를 반환하게 되므로 중복을 제거하기 위해 DISTINCT를 Query문제 추가해준다.
  • DISTINCT 사용시 주의
    • 페이징을 쿼리문에 사용할 수 없다. DB Table의 기준이 바뀌었으므로 내가 원하는 기준으로 적용해서 가져올 수가 없다. 사용시 메모리에 전부 DB값을 올려서 적용하므로 절대 사용하면 안된다. (메모리 에러 발생)
    • 컬렉션 객체는 하나까지만 FETCH JOIN을 사용하는 것을 지향한다. 그 이상은 부정합한 데이터를 반환할 가능성이 있다.

 

V3.1 - 조회시 FETCH JOIN + default_batch_fetch_size 를 적용

  • X to One 객체에 대해서는 FETCH JOIN을 사용해서 가져온다.
  • 나머지 (컬렉션) 객체에 대해서는 LAZY 로딩을 통해서 가져온다.
  • 이때, application.yaml에 (또는 컬렉션 객체에) BatchSize를 적용한다
    • BATCH SIZE를 적용하면 컬렉션 값을 가져올 때 INNER JOIN으로 모두 가져온다.
    • 따라서 N + 1 쿼리 문제를 -> 1 + 1로 바꿔준다. 가져올 때 한번에 가져오므로.
  • 페이징을 쿼리에 적용할 수 있다.

2. 쿼리 DTO 직접 조회

V4 - QueryDto를 생성해서 해당 DTO로 바로 조회

  • JPA에서 DTO를 직접 조회한다.
  • 가져오고 싶은 속성값을 DTO로 만들어서 쿼리 수행 때 바로 생성해서 반환한다.
  • 이때 컬렉션에 대해서는 따로 DTO를 만들고 이미 만들어진 DTO에 삽입해줘야 한다.
  • N + 1 문제가 발생한다.

결론

  1. 엔티티 조회 방식으로 우선 접근
    1. 기본적으로 FETCH JOIN으로 쿼리수를 최적화하자 (컬렉션이 없다면, X to One 관계)
    2. 컬렉션을 최적화
      1. 페이징이 필요하네? -> @BatchSize / hibernate.default_batch_fetch_size 설정 (100 ~ 1000 사이로)
      2. 페이징 없어도 되겠네? -> FETCH JOIN 사용
  2. 엔티티 조회로 안되면, 너무 많은 속성값이 있는 경우 DTO로 바로 조회
  3. DTO 조회도 안되면 NativeSql, 스프링 JdbcTemplate 사용한다

 

엔티티 조회 방식이 좋은 이유!

  • FETCH JOIN, batch size 등을 이용해서 코드를 거의 수정하지 않아도 되고, 옵션만 변경해서 다양한 성능 최적화를 시도할 수 있다.
  • DTO로 줄일 정도면 Redis(레디스) 등 캐시를 사용해야되는 규모까지 된 것
  • JPA가 많은 부분을 최적화를 해준다. (fetch join, batch size 등을 통해서)
반응형
저작자표시 (새창열림)

'스프링 > 스프링부트 API 설계 정리' 카테고리의 다른 글

API 개발 (6) - OSIV 정리  (0) 2021.07.30
API 개발 (4) - One to Many관계 - DTO 직접 조회  (0) 2021.07.29
API 개발 (3) - One to Many관계 - Entity조회 후 DTO로 변환  (0) 2021.07.29
API 개발 (2) - X to One관계  (0) 2021.07.28
API 개발 (1) - 회원 조회, 수정, 생성  (0) 2021.07.28
'스프링/스프링부트 API 설계 정리' 카테고리의 다른 글
  • API 개발 (6) - OSIV 정리
  • API 개발 (4) - One to Many관계 - DTO 직접 조회
  • API 개발 (3) - One to Many관계 - Entity조회 후 DTO로 변환
  • API 개발 (2) - X to One관계
구름뭉치
구름뭉치
구름의 개발일기장
  • 구름뭉치
    구름 개발일기장
    구름뭉치
  • 전체
    오늘
    어제
    • ALL (283)
      • 프로젝트 (23)
        • 토스페이먼츠 PG 연동 시리즈 (12)
        • JWT 방식 인증&인가 시리즈 (6)
        • 스우미 웹 애플리케이션 프로젝트 (1)
        • 스프링부트 기본 보일러 플레이트 구축 시리즈 (2)
        • 마이크로서비스 아키텍쳐 시리즈 (1)
      • 스프링 (43)
        • 스프링부트 API 설계 정리 (8)
        • 스프링부트 RestAPI 프로젝트 (18)
        • 스프링부트 WebSocket 적용기 (3)
        • 스프링 JPA 정리 시리즈 (5)
        • 스프링 MVC (5)
        • 스프링 배치 (2)
        • 토비의 스프링 정리 (2)
      • 기술 학습 (28)
        • 아파치 카프카 (9)
        • 클린 코드 (4)
        • 디자인 패턴의 아름다움 (2)
        • 모던 자바 인 액션 (7)
        • JVM 스레드 딥다이브 (6)
      • Web (25)
        • 정리글 (20)
        • GraphQL 정리글 (2)
        • Jenkins 정리글 (3)
      • 취업 (6)
      • CS (77)
        • 네트워크 전공 수업 정리 (11)
        • OSI 7계층 정리 (12)
        • 운영체제 정리 (19)
        • 데이터베이스 정리 (5)
        • MySql 정리 (17)
        • GoF의 Design Pattern 정리 (12)
      • 알고리즘 (70)
        • 백준 (56)
        • 프로그래머스 (12)
        • 알고리즘 정리본 (1)
      • 기초 지식 정리 (2)
      • 일상 (8)
  • 블로그 메뉴

    • 홈
  • 링크

  • 공지사항

  • 인기 글

  • 태그

    동유럽
    류블라냐
    마우스
    크로아티아
    마우스 패드
    레이저
    부다페스트
    키보드 손목 받침대
    mx master s3 for mac
  • 최근 댓글

  • 최근 글

  • hELLO· Designed By정상우.v4.10.6
구름뭉치
API 개발 (5) - OneToMany관계 정리
상단으로

티스토리툴바