파트너 송금 조회 쿼리 리팩터링으로 응답 속도 5배 개선
목차
무엇을 줄였나
파트너 송금 조회 쿼리가 길었음. 같은 조인을 세 번 반복하고 인라인 뷰도 두 개나 끼어 있었음. 화면 하나에 결과 보여주는 게 전부인데 실행계획 떠보면 풀스캔이 두 번 찍혀서 손봐야 했음.
원본 구조를 거칠게 정리하면 이랬음:
- 송금 본 테이블 + 파트너 정보 조인
- 같은 조건으로 수수료 합계 뽑는 서브쿼리
- 환불 차감용 또 다른 서브쿼리
- 셋을 외곽에서 다시 조인해서 합침
읽기도 어렵고 인덱스도 제대로 안 타고 있었음.
단순화 방향
서브쿼리 두 개를 SUM(CASE WHEN) 으로 합치는 패턴으로 바꿈. 기준 테이블 한 번만 훑고 집계 한 방에 끝남.
SELECT
partner_id,
SUM(CASE WHEN type='SEND' THEN amount END) AS send_amt,
SUM(CASE WHEN type='FEE' THEN amount END) AS fee_amt,
SUM(CASE WHEN type='REFUND' THEN amount END) AS refund_amt
FROM transfer_history
WHERE created_at BETWEEN :from AND :to
GROUP BY partner_id
결과
| 항목 | 변경 전 | 변경 후 |
|---|---|---|
| 쿼리 라인 수 | 약 90 | 약 35 |
| 풀스캔 횟수 | 2 | 0 |
| 평균 응답 | 1.4s | 0.3s |
서브쿼리를 들어내니 (created_at, partner_id) 복합 인덱스가 그대로 먹었음. 별도 힌트도 필요 없음.
배운 점
- 쿼리 길이는 대개 게으름의 누적임. "일단 돌게" 짠 코드가 그대로 남아 있던 거였음
- 같은 테이블에 같은 조건으로 두 번 이상 들어가는 서브쿼리는 거의 항상 CASE 집계로 접을 수 있음
- 실행계획 한 번 안 보고 머지된 쿼리가 제일 무서움. 리뷰에 EXPLAIN 결과 첨부 룰을 추가해야 할 듯
- 리팩터링 PR은 결과 수치를 꼭 본문에 박아둠. 나중에 누가 다시 풀어버리는 걸 막는 가장 싼 방어선임
안 건드린 것
실제 송금/정산 로직은 손 안 댔음. 조회 한 화면만 정리. 비즈니스 룰이 바뀌는 리팩터는 PR을 따로 끊는 게 안전함. 한 번에 묶으면 롤백 단위가 너무 커지고, 문제가 터졌을 때 원인 분리도 어려워짐. 조회 정리 → 도메인 정리 순으로 가는 게 결국 빠름.
다음
댓글 0
첫 댓글 달아줘.