2021.08.17 WIL

Nhahan·2021년 8월 16일
1

항해99 개발일기

목록 보기
31/31

문제점

이번 프로젝트를 하면서 가장 신경 쓴 부분은 쿼리문의 최적화다.

JPA로 메소드를 작성하는 방법으로만 하다보니 메인페이지의 API하나의 쿼리문이 무려 25번 이상 나가는 현상이 벌어졌다.

해결방법

JPQL을 이용해 쿼리문을 작성해 로직을 최적화하기로 했다.

@Query("select r from ChallengeRecord r " +
        "inner join fetch r.member " +
        "Where r.challengeRecordStatus = true and r.challenge = :challenge")
List<ChallengeRecord> findAllByChallenge(Challenge challenge);

@Query("select r from ChallengeRecord r " +
        "inner join fetch r.member " +
        "Where r.challengeRecordStatus = true and r.challenge = :challenge")
Optional<List<ChallengeRecord>> optionalFindAllByChallenge(Challenge challenge);

@Query("select c from ChallengeRecord c " +
        "inner join fetch c.challenge " +
        "inner join fetch c.member " +
        "Where c.challengeRecordStatus = true " +
        "and c.challenge.challengeId in :challengeIdList")
List<ChallengeRecord> findAllByChallengeIdList(List<Long> challengeIdList);

이너조인과 패치로 어느 정도 최적화를 했지만, 그럼에도 불만족스러운 부분이 있었다.
각 테이블에는 여러가지 컬럼들을 가지고 있는데 실제로 쓸 데는 모든 컬럼들을 필요로 하지 않는 점이었다.
예를 들어 Member 테이블에는

이런 컬럼들이 있는데 필요한건 member_id컬럼 뿐이라면 모든 컬럼들을 호출하는건 굉장히 비효율적이라는 생각이 들었다.

그래서 dto로 필요한 컬럼들만 빼서 최적화하는 방법도 있고 실제로 테스트 결과 조회시간이 줄어든 것을 확인할 수 있었지만, 문제는 JPA로 dto를 사용하면 JPQL 작성 시 너무 복잡해서 효율이 굉장히 떨어지고 유지보수하는데 엄청나게 큰 부작용이 있을 것이라 생각했다.

개선점

그래서 팀원과 의논한 결과 QueryDSL을 적용하기로 했다.

와.. 이거 진짜 엄청난 신기술이었다.
그냥 QueryDSL에 반해버렸다.

JPQL의 경우

이런 오류를 컴파일 시에 잡아내지 못한다.
progress와 expected의 파라미터명이 잘못 적용되어있지만 인텔리제이가 이를 잡아내지 못하고 있다. 왜냐하면 @Query의 경우 "" 안에 있는 단순한 스트링에 불과하기 때문에 인텔리제이는 이를 구별해내지 못하는 것이다.

하지만 QueryDSL를 이용하게 된다면,

이렇게 실제로 자바코드로 작성하기 때문에 실수를 할 경우 인텔리제이가 다른 자바코드의 오류를 잡듯이 이를 잡아낼 수 있게 된다.

실제로 리팩토링을 하는 과정에 파라미터를 단일 객체에서 리스트로 변경(ex. memberList를 member로 바꾼다거나)하는 과정에서 이를 알아채지 못해 왜 오류가 발생해 시간을 허비한 적이 있다.
QueryDSL을 사용하면 이런 것도 모두 잡아낼 수 있는 것이다.

이야기가 조금 샌 거 같은데, QueryDSL을 적용하게 되면 dto도 훨씬 깔끔하게 적용할 수 있다!

마치 원시인이 불을 발견했을 때와 같은 느낌이다. 이건 혁명이다...

0개의 댓글