이 문서를 통해 아래 질문들에 답할 수 있게 됩니다.

  • 운영 DB에서 분석 DB를 분리해야 하는 신호는 무엇인가?
  • replica, warehouse, mart 중 어떤 분리 수준을 선택해야 하는가?
  • 분석 쿼리가 운영 API에 영향을 주는지 어떤 지표로 확인하는가?
  • 분리 이후에도 재처리와 품질 검증을 어떻게 보장하는가?

개요

운영 DB와 분석 DB를 분리하는 기준은 “데이터가 많아졌는가”만이 아니다.

운영 요청과 분석 조회가 같은 저장소, 같은 connection, 같은 index, 같은 lock 범위를 경쟁하기 시작하면 분리를 검토한다.

분리는 성능만을 위한 조치가 아니다.

분석 요구의 지연 허용치, 재계산 가능성, 지표 정의 owner를 운영 transaction에서 떼어내는 작업이다.

원리

운영 DB는 사용자 요청을 짧고 안정적으로 처리해야 한다.

분석 DB는 많은 row를 읽고, 여러 source를 조합하고, 같은 기간을 다시 계산할 수 있어야 한다.

두 요구가 충돌하면 다음 문제가 생긴다.

  • dashboard query가 API connection pool을 점유한다.
  • GROUP BY가 buffer cache를 밀어낸다.
  • replica query가 길어져 replica lag가 커진다.
  • 지표 기준이 repository SQL과 dashboard SQL에 흩어진다.
  • 리포트 보정을 위해 운영 row를 직접 수정하려는 압력이 생긴다.

분리 수준

수준선택 상황장점한계
운영 DB 직접 조회데이터 작고 내부 확인용빠르고 단순함운영 부하와 지표 분산 위험
Read Replica읽기 부하 분산 필요운영 primary 보호lag와 장기 쿼리 문제 남음
Summary Table반복 집계가 작음백엔드가 관리 가능재처리와 정의 관리 필요
Warehouse여러 source 통합공통 분석 기반적재 파이프라인 필요
Mart특정 지표 반복 소비빠른 조회와 SLA정의 변경 관리 필요

분리는 한 번에 끝나는 프로젝트가 아니다.

분석 요구가 커질수록 직접 조회, replica, summary, warehouse, mart 순서로 책임을 옮길 수 있다.

운영 DB 직접 조회를 허용할 때

운영 DB 직접 조회가 항상 나쁜 것은 아니다.

개발 초기, 내부 관리자 화면, 낮은 빈도의 점검 쿼리는 직접 조회가 더 실용적일 수 있다.

다만 다음 조건을 둔다.

  • 조회 기간 제한
  • timeout 제한
  • peak time 실행 금지
  • 인덱스와 실행 계획 확인
  • 종료 조건 또는 대체 계획
SELECT DATE(created_at) AS order_date,
       COUNT(*) AS order_count
FROM orders
WHERE created_at >= current_date - interval '7 days'
GROUP BY DATE(created_at);

이 쿼리는 초기에는 충분할 수 있다.

하지만 기간이 1년으로 늘고 여러 dashboard가 동시에 실행하면 분리 후보가 된다.

분리 신호

분리는 다음 신호가 반복될 때 검토한다.

  • 분석 쿼리 때문에 API latency가 증가한다.
  • report query가 connection pool을 오래 점유한다.
  • 같은 지표 SQL이 여러 곳에 복사된다.
  • replica lag 때문에 “오늘 수치”가 매번 달라진다.
  • 분석 요구가 여러 서비스의 데이터를 join한다.
  • 과거 데이터를 다시 계산해야 하는 일이 잦다.
  • dashboard freshness를 사용자에게 설명해야 한다.

하나의 신호만으로 큰 플랫폼을 도입할 필요는 없다.

하지만 여러 신호가 함께 나타나면 운영 DB 안에서 해결하려는 접근이 비용을 키운다.

재처리 기준

분리 후에는 재처리 기준이 더 중요해진다.

운영 DB에서 직접 조회할 때는 매번 현재 상태를 읽는다.

warehouse나 mart로 분리하면 특정 시점과 범위의 복사본을 다룬다.

source: orders, payments
extract_key: updated_at
target: fact_order_payment
range: 2026-06-01..2026-06-30
mode: overwrite partition
validation: source_count, paid_amount_sum, freshness

분리된 분석 DB는 source range와 target partition을 알아야 다시 만들 수 있다.

운영 지표

  • api_db_latency_p95: 분석 쿼리가 API DB 시간을 밀어 올리는지 본다.
  • connection_pool_active: 분석 조회가 pool을 점유하는지 본다.
  • replica_lag_seconds: replica 기반 분석의 최신성 위험이다.
  • analytics_query_timeout_count: 분석 쿼리 비용이 커지는 신호다.
  • warehouse_freshness_lag: source와 warehouse 사이 지연이다.
  • mart_rebuild_count: 반복 재계산 필요성을 보여준다.

지표는 “느리다”를 “어느 저장소와 어느 경계가 느린가”로 바꿔 준다.

개인 프로젝트 기준

개인 프로젝트에서는 summary table부터 시작하는 편이 실용적이다.

예를 들어 order_daily_summary를 하루 한 번 갱신하고, refreshed_attarget_date를 남긴다.

운영 DB 안에 있어도 API table과 summary table의 책임을 나누면 분리 사고를 연습할 수 있다.

기업 운영 기준

기업에서는 운영 DB 보호와 지표 계약을 분리해서 본다.

DBA나 인프라 팀은 primary 부하, replica lag, backup, storage를 본다.

데이터 팀은 warehouse 적재, mart build, freshness, 품질 rule을 본다.

백엔드 팀은 원천 의미, key, status, 삭제/취소 표현, schema 변경 계획을 제공한다.

실전 팁

  • 분석 요구가 API 응답에 꼭 필요한 값인지 먼저 묻는다.
  • 몇 분 또는 몇 시간 지연을 허용할 수 있으면 분리 후보로 본다.
  • replica를 쓰더라도 lag와 장기 쿼리 제한을 둔다.
  • summary table에는 갱신 시각과 재실행 parameter를 남긴다.
  • warehouse로 옮길 때 source의 business rule을 함께 문서화한다.

위험 신호!

  • 대시보드 장애를 API DB 인덱스 추가만으로 해결하려 한다.
  • 분석 쿼리가 운영 peak time에 제한 없이 돈다.
  • replica lag를 모르고 “실시간 리포트”라고 표시한다.
  • summary table을 수동 update하고 재계산 절차가 없다.
  • 분리 후 품질 검증 없이 dashboard를 공개한다.

확인 질문

확인 질문

  • 운영 DB와 분석 DB를 분리해야 하는 가장 강한 신호는 무엇인가?
    • 분석 조회가 사용자 요청의 latency, connection, lock, replica lag에 반복적으로 영향을 주는 것이다.
  • read replica만으로 해결되지 않는 문제는 무엇인가?
    • 지표 정의 분산, freshness 설명, 재처리, mart 품질 검증은 replica만으로 해결되지 않는다.
  • 분리된 mart를 다시 만들려면 무엇을 기록해야 하는가?
    • source range, target partition, transformation version, 검증 SQL, build id가 필요하다.

참고 문서