API 성능 테스트 (with fetch join)
(1) 예상
- 1번 방식) 기존 api에서 center 정보 가져올 때
- 기존 쓰던 대로 api 쓰면 됨(서버 통신 그대로)
- 센터 정보 찾는 쿼리 날릴 때 최적화 쉬움
- jpa에서 제공하는 fetch join+batch 기능을 사용해서 쿼리 수가
n/배치사이즈으로 줄어들고 중복데이터는 안가져와서 최적화 쉬움 - select * from center where id in (1,2,3)
- 같은 트랜잭션 내에서 조회해오기에 데이터 일관성을 보장할 수 있음
- 2번 방식) 새로운 api에서 center 정보 추가로 가져올 때
- api를 한 번 더 날려야 함(서버 통신 + 1)
- 센터 정보 찾는 쿼리 날릴 때 최적화 어려움
- id 100개면 쿼리도 100번 날려야 함 →
n - select * from center where id=1
- select * from center where id=2
- 설령 in 절 사용하더라도 배치 처리 따로 또 해주지 않으면 최적화 힘듦
- select * from center where id in (1,2,1) → 중복은 in이 알아서 처리해준다.
- 배치 처리만 안된다.
(2) 결과
- 아래 코드를 컨트롤러 단에 넣어주어 측정했다. 아 근데 포스트맨 사용 중이면 포스트맨에도 실행 시간 뜬다.
- 2번 방식 테스트 전 짧막한 수정)
- 어….. ㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋ 70개 가져오는데 12초
- 문제의 레거시 쿼리…..
- findById 사용하게 바꿔줬다. fetchAll은 필요가 없으니,, 아마 센터 상세 조회 api가 저 쿼리 사용하는 함수를 같이 쓰고 있어서 문제일 텐데 일단 테스트용이니 잠깐 바꿔줘자.
- 3.8초로 줄었지만 그래도 여전히 오래 걸린다.
- 조금 더 최적화해서 in절 사용하게 해보자..
- 1번 방식) fetch join
- 0.734초
- 2번 방식) 일반 select
- 70개 가져오는 데 0.3초 + 4.1초
- in절 사용할 땐 70개 가져오는 데 0.3초 + 0.27초 = 0.57초
참고
(3) 후속 테스트
- 1번 방식과 2번 방식의 차이가 애매한데, 좀 더 많은 양의 데이터로 좀 더 정교하게 비교해보기로 했다.
- 일단 가져오는 데이터 필드를 똑같게 만들어줬고 데이터 양을 둘다 똑같이 902개로 늘렸다.
- MySQL 무순서성 : 순서 보장 안되므로 정렬 넣어줬다
- 추가로.. hashMap을 쓰고 있어서 더욱 순서 보장이 안되었다. LinkedHashMap으로 바꿔줬다. 사실 이것만 해줘도 순서 보장 된다.
순서 보장
- 1번 방식) fetch join (select in)
- 0.688초 ~ 0.9xxx초
기존 쿼리
- 2번 방식) select in
- 0.554초 + 0.322초 = 0.8xxx초
기존 쿼리
select in 쿼리
- 여전히 비슷하다. 더이상 데이터 늘리려면 query string 자리가 부족해지기에 여기까지만 테스트하고 정리했다.
(4) 결론
- 1번 방식을 사용하기로 했다. 직적 쿼리 짤 필요 없이 같은 성능으로 간단히 최적화해주기 때문이다.
N+1문제와 batch
- 정의) 연관 관계가 설정된 엔티티를 조회할 경우에 조회된 데이터 갯수(n) 만큼 연관관계의 조회 쿼리가 추가로 발생하여 데이터를 읽어오는 현상
- 특징) batch를 사용해 fetch join을 하면 in 절로 select 해와 N+1 문제를 해결할 수 있다.
- 참고)

