이번 최적화는 성능 최적화 보다는 유지보수적 측면에서 최적화 하는 것에 집중 하였습니다.
실전! 스프링 부트와 JPA 활용2 - API 개발과 성능 최적화
인프런에서 강의를 듣고 몇달전 프로젝트 하던 것을 최적화 해보기로 했다.
오늘 최적화 해볼 쿼리다!

음.. 그러니까..
내가 했음에도 보기 좀 지져분했다.
이 JPQL을 작성할 당시에는 내가 가져오고자 하는 데이터들이 4개(Member, 게시판, 게시판 댓글, 게시판 이미지) 엔티티에 나눠서 담겨있기에
필요한 만큼만 DTO로 받아와서 성능적인 면으로 최적화하고자 했었다.
그 당시엔 최선이라 생각했었지만 강의를 듣다가 사실상 DTO로 필요한 정보만 빼오는 것이 가시성도 별로고
엔티티들을 통으로 가져와도 성능 차이가 크지 않고 유지보수적으로 매우 유리하고 나중에 성능이슈 생기면 그때 바꿔도 늦지 않는다고 하기도 하고 다 맞는 말이라 판단이 들어서 다시 쿼리를 짜봤다.
그래서 두번째 쿼리다.
보기에는 가시성도 매우 좋아졌고 유지보수도 매우 간편해보인다.
이 쿼리의 의도는 OeBoard에 필드로 있는 Entity들이 지연 로딩으로 설정되어 있어서 join fetch로 즉시 로딩을 하기 위한 의도였고
실행해 본 결과 MultipleBagFetchException이 발생했다 이유는 게시판 이미지와 댓글 엔티티가 OeBoard와 OneToMany관계이기 때문이었다.
Hibernate에서는 여러 개의 'bag'(순서 없는 List 형태) fetch join을 허용하지 않고, 이를 시도하면 MultipleBagFetchException을 일으킨다고 한다 혹시 Set을 사용하면 가능할까 했지만 그럼 Page클래스를 사용함에 제한이 생기기 때문에(쿼리를 실행하고 반환받은 값은 Page의 contens필드로 들어오게 되는데 contens는 List이다)
좀 더 알아보니 MultipleBagFetchException가 아니더라도 join fetch를 사용하면 실제 쿼리를 실행할 때
원래는 Spring Data JPA가 Pageable 객체에 설정된 limit과 offset 정보를 바탕으로 자동으로 Limit절을 추가해 주지만 패치조인을 쓴다면 Limit절이 빠지고 where절을 만족하는 모든 값들이 넘어와서 메모리에 담고 페이지네이션이 된 것처럼 보이게 한다.
이건 나중에 데이터가 커지면 수정하고 그럴 것이 아니라 처음부터 이렇게 개발하면 안 될 거 같다라고 판단했고 패치조인 전략은 접기로 했다...
그럼 어떻게 해야 유지보수도 잡고 가시성도 잡을까 고민하던중 엔티티를 필드로 가지고 있는 DTO로 받으면 괜찮지 않을까? 생각했고 실행해봤다.
최종 쿼리이다. 많이 보기 편해졌다 계속 보다보니 착시인가?
보면 게시판이랑 멤버 엔티티만 통으로 받고 댓글 수나 썸네일로 보여줄 이미지 하나는 단일로 받고 있다.
일단 이런 식으로 혹시 수정이 생긴다면 이쪽 엔티티에서 생기겠다 싶은 엔티티만 직접적으로 받고 나머지는 컬럼을 지정해서 가져오는 것으로 타협을 봤다.
실제 처음 복잡해 보이는 쿼리와 최종 쿼리의 성능을 비교해 보면 하나의 페이지를 요청할 때 로컬에서10ms ~ 15ms초 정도 차이가 있었고 이 차이가 유의미한 수준인지는 아직 파악이 안된다.
마지막으로 일단 확실히 보기는 편해진 거 같아서 기분은 좋았다.
하지만 엔티티를 그대로 반환할 수는 없기 때문에 반환용 DTO를 하나 만들어야 하는 것이 단점이긴 하지만 막상 작성하다 보니 그리 어려운 로직도 아니고 그래봐야 service에서는 한 줄 추가되는 정도라 적어도 지금 상황에선 큰 단점은 아니라 생각했다.
아쉬운 점은 성능 테스트하는 법을 잘 몰라서 이 정도는 허용되는 범위인지 치명적인지 구분이 안 가는 것이었고 그래서 다음 공부할 내용은 성능 테스트로 결정했다! 끝!
'spring > 개발 - OEasy' 카테고리의 다른 글
[Spring][JPA] Querydsl을 사용하여 동적쿼리 처리 (1) | 2025.06.18 |
---|---|
Spring - stomp를 사용하여 채팅과 투표기능 개발 (0) | 2024.12.11 |
Spring - 스케줄러와 기상청 API를 이용한 [오이지수] 개발 (1) | 2024.12.09 |