Search

10만개의 엔티티 조회 성능 개선 시도

Created
2024/11/06 00:58
태그
개발
Status
Done

문제 상황

관리기 응시자 분석 현황 조회 기능 구현 중 발생
관리기의 필터링 조건 중 응시가능시작일, 응시가능종료일, 결과지 조회 항목의 데이터가 데이터베이스의 테이블에 저장된 것이 아닌 비즈니스 로직으로 도출되어야 함
응시자 분석 현황 조회 시 적용되는 위 필터 조건들을 적용하기 위해서는 페이지네이션 사용 불가
이를 해결하기 위해서는 온 메모리 페이지네이션, 캐싱, 테이블 재정규화가 있지만 당장 적용 가능한 부분은 온 메모리 페이지네이션 밖에 없음
전체 데이터를 메모리에 올려 직접 페이지네이션을 구현
QC 서버 기준 면접 완료 응시자 엔티티 조회 98000 여 개 조회 필요
약 10만 개의 데이터를 메모리에 올리기 위해 수행되는 쿼리의 응답 시간이 너무 오래걸리는 상황

구현 및 개선 과정

1. 엔티티 조회 방식

사용해야하는 엔티티 객체가 많고, N+1 문제 등으로 인해 Fetch Join을 통한 여러 엔티티를 한 번에 조회하는 방식으로 구현
⇒ 응답까지 17분 / 여러 엔티티를 Fetch Join 해오는 쿼리 수행 시간 15분 소요
조회 성능이 나쁜 이유
QC 서버 기준 면접 완료 Candidate 엔티티 98000 여 개 조회 필요
응시자 엔티티와 채널 엔티티에 포함된 Formula로 인해 서브쿼리 8만개 수행되는 것과 동일한 상태
따라서 Formula를 제거하기 전에는 위 방식의 조회 사용 불가

2. Projection 조회 방식

Projection 방식으로 조회 후 N+1이 터지도록 방치하는 방식으로 변경
응답까지 대략 33 ~ 36초 소요
17분에 비하면 빠르지만, 여전히 사용하기 어려울 정도의 속도
역량검사 결과지 여부 조회 시 그래프 탐색과 양방향 OneToOne 매핑으로 인한 무수히 많은 N+1 쿼리 발생으로 속도 저하

3. Projection 조회 방식 + Fetch Join

마찬가지로 Projection 방식으로 조회 후 이후, 필요한 필수적인 엔티티 객체들에 대해서만 Fetch Join으로 조회하도록 추가
응답까지 대략 12 ~ 14초 소요
시간이 절반으로 줄었지만, 여전히 느림

4. Projection 조회 방식 + Fetch Join + 병렬 처리

위 방식에서 가장 오래걸리고 외부 API를 호출하는 부분인 역량검사 결과지 여부 조회를 병렬 처리
응답까지 대략 11 ~ 13초 소요
1초 정도의 개선 효과
QC WAS 서버가 돌고 있는 인스턴스의 코어 수와 CPU 성능적 제약 때문에 개선 효과가 없는 것으로 추정

5. 쿼리 순서 변경 및 최적화

병렬 처리를 롤백 후 필요한 데이터를 다른 쿼리에서 불러온 후 IN절을 통해서 최적화
응답까지 대략 10 ~ 12초 소요
약 1초 정도의 개선 효과

6. 조회 조건 추가

Formula 제거 외에는 더 이상 개선의 여지가 없다고 생각되어, 전체 조회 레코드를 줄이기 위해 기획 변경으로 조회 시 조건 추가
기존 : 면접 완료 상태의 응시자 전부
변경 : 면접 완료 상태의 응시자 중 최근 2주 이내에 응시 완료한 응시자 + 테스트 채널인 경우 제외
응답까지 400 ~ 600ms

결론

조건을 추가하여 응답 속도를 올렸지만, 몬스터의 응시자가 많아지게 되어 2주 내에 면접 완료하는 응시자가 많아진다면 다시 쿼리 속도가 급격하게 저하될 가능성이 있다.
이를 개선하기 위해서는 Formula 제거, OneToOne 양방향 매핑 제거를 통한 불필요한 N+1 삭제가 필요하다.