통계 데이터와 성능 문제
- 서비스 초기에는 원본 테이블(
orders )을 직접 GROUP BY 하여 통계를 내도 문제가 없다.
- 데이터가 수천만 건 이상 쌓이면 통계 쿼리가 실행될 때 CPU와 메모리를 과다하게 사용하여 서비스 전체 성능을
저하시킨다.
- 통계 조회로 인해 고객의 주문/결제 트랜잭션이 느려지거나 장애가 발생할 수 있다.
- 대용량 트래픽 환경에서는 통계 처리와 원본 데이터 처리를 분리해야 한다.
통계 테이블 설계
- 통계를 위한 별도의 요약 테이블(Summary Table)을 생성하여 해결한다.
- 배치(Batch) 프로그램을 통해 사용자가 적은 새벽 시간에 원본 데이터를 집계하여 통계 테이블에 저장한다.
- 통계 테이블은 하루에 한 행만 생성되므로 데이터 양이 획기적으로 줄어들어 조회 속도가 매우 빠르다.
- 실시간 데이터를 조회할 수 없다는 단점이 있다.
주간, 월간 통계의 효율적인 처리
- 일별 통계 테이블(
daily_sales_stats )만 있으면 주간, 월간, 연간 통계를 별도로 만들 필요가 없다.
- 일별 통계 데이터는 양이 매우 적기 때문에, 이를 다시
GROUP BY 하여 월간/연간 통계를 계산해도 비용이 거의 들지 않는다.
- 불필요한 월간/연간 테이블 생성은 관리 포인트를 늘리므로 지양해야 한다.
실시간 통계와 하이브리드 설계
- 실시간 통계가 필요한 경우, 통계 테이블(과거 데이터)과 원본 테이블(오늘 데이터)을 결합하는 하이브리드 방식을 사용한다.
UNION ALL 을 사용하여 두 테이블의 데이터를 합쳐서 조회한다.
- 오늘 데이터는 양이 적고 인덱스를 활용할 수 있어 실시간 집계 부하가 적다.
- 대용량 데이터 환경에서도 성능과 실시간성 모두를 확보할 수 있는 전략이다.
멱등성 설계
- 통계 배치는 몇 번을 재실행해도 결과가 같아야 하는 멱등성(Idempotency)을 보장해야 한다.
- 기존 값에 더하기를 하는 증분 업데이트(
UPDATE ... + value ) 방식은 재실행 시 데이터 중복(뻥튀기) 문제가 발생하므로 피해야 한다.
- 지우고 다시 쓰기(DELETE & INSERT) 전략을 사용하면 언제든 배치를 재실행하여 데이터를 복구하거나 과거 데이터 수정(환불 등)을 반영할 수 있다.
마이크로 배치
- 하루 데이터량이 너무 많아 실시간 집계조차 부담스러울 때 사용하는 전략이다.
- 1분, 5분 등의 짧은 주기로 오늘 데이터를 집계하여 별도의 장중 통계 테이블에 저장한다.
- 조회 시에는 '과거 통계 테이블'과 '장중 통계 테이블'을 결합하여 보여준다.
- 실시간성은 약간 떨어지지만(예: 5분 지연), 조회 성능을 극대화하고 DB 부하를 차단할 수 있다.
UPSERT 최적화
- 빈번한 마이크로 배치에서
DELETE & INSERT 를 사용하면 인덱스 재구축, 로그 생성 등 DB 리소스 낭비가 심하다.
- UPSERT(
INSERT ... ON DUPLICATE KEY UPDATE ) 구문을 사용하면 데이터가 없을 땐 넣고, 있을 땐 값만 수정한다.
- UPSERT는 불필요한 삭제와 생성을 방지하여 성능이 뛰어나며, 덮어쓰기 방식이므로 멱등성도 보장된다.
- 일별 배치(새벽)는 명확한 관리를 위해
DELETE & INSERT 를, 실시간 마이크로 배치는 성능을 위해 UPSERT를 사용하는 것이 권장된다.
통계 데이터 설계 핵심 정리
- 처음에는 GROUP BY로 시작한다. 데이터가 적을 때는 이것으로 충분하다.
- 성능이 문제되면 일별 통계 테이블을 도입한다. 1년 365행, 10년 3,650행이면 대부분의 조회가 해결된다.
- 주별, 월별 통계는 일별 통계를
GROUP BY하면 된다. 별도 테이블은 대부분 불필요하다.
- 실시간이 필요하면 통계 + 오늘 원본 데이터를 조합한다. 오늘 하루치는 양이 적다.
5/ 멱등하게 설계한다. 문제가 있으면 쿼리 수정하고 배치 재실행으로 해결할 수 있어야 한다.
- 성능이 중요하면 마이크로 배치를 고민한다.
UPSERT를 사용하면 SELECT + INSERT/UPDATE 문제를 효과적으로 처리할 수 있다.
Reference: 김영한의 실전 데이터베이스 - 설계 2편, 실무에서 반드시 마주치는 9가지 설계 패턴