[상품 썸네일 배지 성능 개선기] 2.쿼리 호출 100회 → 1회, 구조 자체를 바꿨다
1편에서는 쿼리 튜닝과 호출 방식 개선을 통해 과도한 row 스캔 문제를 해결했습니다.
이번 글에서는 그 구조를 더 확장하여, 쿼리 호출 횟수 자체를 줄이는 방향으로 개선한 사례를 다룹니다._
🧩 남아 있던 문제
1차 개선 이후, 배지 조회 쿼리의 성능 자체는 충분히 가벼워졌습니다.
하지만 여전히 상품 수만큼 반복 호출된다는 구조적 한계가 있었습니다.
- 예: 상품 목록에 100개의 상품이 있을 경우 → 쿼리 100회
- 조회 1회당 부하는 작지만, 호출 자체가 반복되며 리소스를 지속적으로 점유
즉, “가벼운 쿼리”를 “많이” 날리고 있는 상황이었습니다.
이 반복을 없앨 수는 없을까?가 이번 개선의 출발점이었습니다.
🛠 개선 아이디어: 조회 구조 자체를 일괄 처리 방식으로 전환
기존 구조 (AS-IS)
- 상품 1개 → 배지 쿼리 1회
- 상품 100개 → 배지 쿼리 100회
개선 구조 (TO-BE)
- 상품 100개 → prod_code를 모아 한 번에 조회
- 배지 전체를 한 번에 가져온 뒤, 로직에서 상품별로 매칭
// prod_code를 최대 100개 단위로 나눠 일괄 조회
const chunks = split(prodCodes, 100);
for (const chunk of chunks) {
fetchBadgesByProdCodes(chunk);
}
주의사항: IN 조건의 한계 대응
디자인모드 상으로는 한 페이지 당 최대 98개의 상품이 호출가능하므로 현실적으로는 문제가 없지만 향후 유연성을 확보하기 위해 청크 처리 방식을 도입했습니다.
- prod_code가 100개 이상일 경우 → 100개씩 분할하여 순차 처리
- 안전성과 확장성을 동시에 확보
✅ 개선 효과
항목 | 개선 전 | 개선 후 |
---|---|---|
쿼리 호출 횟수 | 상품 수만큼 호출 (예: 100회) | 최대 1~2회로 일괄 조회 |
DB/네트워크 부하 | 상품 수에 비례하여 선형 증가 | 거의 고정 수준 유지 |
로직 복잡도 | 상품마다 개별 처리 로직 필요 | 일괄 조회 후 매핑 처리 |
확장성 | 상품 수 증가 시 부하 동반 증가 | 상품 수 무관하게 일정 |
장애 가능성 | 과도한 호출로 인한 커넥션 부담 위험 | 호출 횟수 최소화로 안정 |
마무리하며…
이번 개선은 단순히 쿼리 성능을 높이는 수준을 넘어,
조회 구조 자체를 재설계하여 호출 횟수를 원천적으로 줄인 사례였습니다.
이러한 구조적 접근은 단기적인 효과뿐 아니라
서비스가 확장될 때 발생할 수 있는 잠재적인 병목을 사전에 차단할 수 있다는 점에서 더욱 의미가 큽니다.
앞으로도 반복 호출, 불필요한 쿼리 구조, 확장성에 영향을 주는 패턴들을 지속적으로 점검하고 개선해 나가야겠습니다.
(원래 시리즈로 할 생각이 없었는데, 한 아이템에서 두 개선건이 나오게되었네요 😅)
댓글남기기