DB 읽기 비용 최적화 방향 통합

DB 읽기 비용 최적화 방향 통합

ADR-360 DB 읽기 비용 최적화 방향 통합

1. Metadata

  • ADR ID: ADR-360
  • Status: draft
  • Date: 2026-03-19
  • Owner: YSY
  • Related ADRs: ADR-180, ADR-220, ADR-270, ADR-290, ADR-295, ADR-350
  • Supersedes: 없음
  • Superseded By: 없음

2. Context

  • 현재 DB 비용 최적화 과제는 파트너 운영 화면 한 곳의 문제로 끝나지 않는다.
  • 비용에 직접 영향을 주는 항목은 쿼리 횟수만이 아니라 RLS 스캔 범위, 반환 row 수, payload 크기, polling 주기, 같은 세션 내 중복 조회까지 포함한다.
  • 현재 읽기 패턴은 다음처럼 성격이 다른 데이터를 동일한 방식으로 다루는 경향이 있다.
  1. 슬롯 발행/종료에 따라 자주 바뀌는 실시간 운영 상태
  2. 최근 목록만 필요하지만 전체 이력을 읽는 운영 목록
  3. 전일 또는 기간 기준으로 닫힌 집계 데이터
  4. 파트너 전환과 무관한 정적 카탈로그
  5. 다른 조회에 종속되지 않아도 되는 보조 메타데이터
  • 이 상태에서는 화면 하나를 빠르게 만드는 단기 수정은 가능해도, 기능이 늘수록 읽기 비용과 응답 지연이 함께 커진다.
  • 따라서 이번 결정의 범위는 특정 쿼리 튜닝이 아니라 DB 비용 최적화의 기준 방향을 정하는 것이다.

3. Domain Decision

  1. DB 읽기 비용 최적화는 화면이 아니라 read class 기준으로 설계한다.
  2. 기본 read class는 다음 5가지로 고정한다.
  3. live current: 지금 또는 오늘 기준으로 계속 변할 수 있는 상태
  4. bounded operational list: 최근/활성 범위만 필요한 운영 목록
  5. historical snapshot: 전일 또는 기간 기준으로 닫힌 집계
  6. static catalog: 세션 단위 재사용 가능한 저변화 데이터
  7. auxiliary metadata: 필요한 시점에만 읽으면 되는 보조 정보
  8. 비용 최적화의 우선순위는 총 쿼리 수 절감이 아니라 활성 세션당 반복적으로 터지는 hot path 절감에 둔다.
  9. 같은 도메인 데이터라도 read class가 다르면 별도 조회 계약과 캐시 규칙을 사용한다.
  10. 현황이라는 용어는 live current에만 사용하고, 전일 또는 기간 기준 데이터에는 사용하지 않는다.
  11. 전일 스냅샷과 기간 추이는 historical snapshot으로 분류하며, 실시간 현황과 같은 갱신 기대치를 갖지 않는다.

4. Product Decision

  1. 파트너 대시보드와 운영 화면은 오늘/현재전일/기간을 명시적으로 분리한다.
  2. 대시보드의 현황은 오늘 기준 또는 현재 기준 데이터만 의미한다.
  3. 전일 마감 데이터는 별도 전일 요약, 전일 마감, 기준일 요약과 같이 닫힌 데이터임이 드러나는 이름으로 노출한다.
  4. 기간추이업종 분석은 어제까지 확정된 데이터를 기본 SoT로 사용한다.
  5. 파트너 운영 화면의 기본 진입은 요약 확인을 우선하고, 과거 이력과 편집 상세는 명시적 진입 시점에만 연다.
  6. 사용자가 한 세션 안에서 같은 파트너를 반복 방문할 때 같은 정적 데이터와 닫힌 집계를 매번 처음부터 다시 읽지 않는다.

5. UX Decision

  1. 실시간 운영 상태는 mutation 결과와 앱 로컬 상태를 우선 반영하고, 필요한 경우에만 서버 재검증을 수행한다.
  2. 닫힌 집계 데이터는 기준일 라벨과 함께 캐시를 적극 허용한다.
  3. 사용자가 인지하는 새로고침 필요성은 실제 변동 가능성이 있는 영역에만 남긴다.
  4. 파트너 전환과 무관한 정적 카탈로그는 화면 재진입마다 skeleton을 다시 만들지 않는다.
  5. 긴 이력 목록은 기본 로드 범위를 제한하고, 더보기 또는 페이지네이션으로 확장한다.
  6. 주기적 polling은 기본 전략이 아니라 보조 전략으로 사용한다.

6. Tech Decision

6.1 기본 원칙

  1. live current는 전체 재조회보다 write result patch + 선택적 재검증을 우선한다.
  2. bounded operational list는 기본 조회 범위를 명시적으로 제한한다.
  3. historical snapshot은 날짜 키 기반 캐시를 허용한다.
  4. static catalog는 파트너 선택과 분리된 세션 캐시를 기본으로 한다.
  5. auxiliary metadata는 다른 hot query의 종속 effect로 읽지 않는다.

6.2 대시보드 방향

  1. 현황 카드는 오늘/현재 기준 데이터만 사용한다.
  2. 기간추이업종 분석partner_metrics_daily 또는 동등한 일별 snapshot SoT를 사용한다.
  3. 전일 snapshot이 필요하면 historical snapshot으로 노출하고, 현황과 같은 영역으로 섞지 않는다.
  4. 기간추이업종 분석partnerId + range + toDate 기준으로 앱 캐시를 허용한다.
  5. snapshot 응답에는 기준일과 updated_at 또는 동등한 freshness 필드를 포함한다.

6.3 파트너 운영 방향

  1. 슬롯 목록 기본 조회는 active + recent closed 범위로 제한한다.
  2. entitlement, QR 상태, 파트너 기본 상태는 하나의 요약 read model로 합칠 수 있으면 합친다.
  3. mutation 성공 후 전체 entitlement 재조회는 기본 전략으로 사용하지 않는다.
  4. subscription_plans, subscription_addons는 세션 범위 캐시로 올린다.
  5. 편집용 상세 필드와 이미지 배열은 hot path에서 분리한다.

6.4 사용자 탐색 방향

  1. public_get_nearby_slots 같은 대량 hot read는 polling 주기, 위치 변화, 화면 focus를 함께 고려한 적응형 전략으로 줄인다.
  2. 즐겨찾기 파트너 메타데이터 조회는 슬롯 새로고침 주기에 종속시키지 않는다.
  3. 위치 기반 탐색은 반경, 정렬, 필드 집합, 재호출 조건을 함께 최적화한다.

6.5 캐시 및 무효화 규칙

  1. live current는 아래 이벤트에서 우선 무효화하거나 patch한다.
  2. 슬롯 발행
  3. 슬롯 종료
  4. 구독 변경
  5. 파트너 전환
  6. 수동 새로고침
  7. historical snapshot은 아래 경우에만 재조회한다.
  8. 날짜 경계가 바뀐 경우
  9. 기준일이 바뀐 경우
  10. 수동 새로고침
  11. is_stale 또는 동등한 stale 표시가 있는 경우
  12. static catalog는 파트너 전환만으로 무효화하지 않는다.
  13. auxiliary metadata는 해당 화면 또는 모달 진입 시점에만 읽는다.

6.6 비채택 방향

  1. 근거 없이 모든 문제를 초대형 단일 RPC로 몰아넣지 않는다.
  2. 정확한 invalidation 규칙 없이 전면적 polling 확대를 채택하지 않는다.
  3. 서버 SoT를 흐리는 장기 로컬 캐시를 기본 전략으로 사용하지 않는다.

7. Ops Decision

  1. 비용 최적화의 기준 지표는 월 청구액만이 아니라 active session당 DB invocation, row 수, payload 크기, P50/P95 응답시간을 함께 본다.
  2. 화면별 read budget을 문서와 QA 기준으로 관리한다.
  3. 우선순위는 아래 순서로 둔다.
  4. 사용자 근처 슬롯 탐색
  5. 파트너 운영 hot path
  6. 즐겨찾기/보조 메타데이터
  7. 대시보드 historical cache
  8. 신규 read model이나 snapshot 도입 전후로 호출 수와 payload 절감 효과를 비교한다.
  9. 비용 문제와 성능 문제는 같은 운영 항목으로 추적한다.

8. Implementation Contract

8.1 Read Class Contract

  • live current는 오늘/현재 상태를 의미한다.
  • historical snapshot은 전일 또는 기간 기준 닫힌 데이터를 의미한다.
  • 같은 화면 안에서도 두 계약을 혼용할 수 있지만, 명칭과 캐시 정책은 분리해야 한다.

8.2 Dashboard Contract

  • 현황은 전일 snapshot을 직접 의미하지 않는다.
  • 전일 snapshot을 보여줄 경우 기준일을 함께 노출해야 한다.
  • 기간추이업종 분석은 앱 캐시를 허용한다.
  • snapshot 응답은 최소 metric_date와 freshness 필드를 포함해야 한다.

8.3 Partner Ops Contract

  • 슬롯 목록 기본 로드는 전체 이력이 아니라 제한된 범위를 사용한다.
  • mutation RPC는 가능하면 화면에 필요한 최소 summary를 함께 반환한다.
  • 정적 카탈로그는 파트너 전환 때 재조회하지 않는다.

8.4 User Explore Contract

  • 근처 슬롯 조회는 기본적으로 앱 foreground, 위치 변화, 수동 refresh 조건을 함께 본다.
  • polling은 비용 예산 안에서만 허용한다.
  • 즐겨찾기 메타데이터는 슬롯 목록 refresh effect에 직접 묶지 않는다.

8.5 Observability Contract

  • 최적화 전후 비교가 가능하도록 화면 단위 호출 수와 payload를 기록할 수 있어야 한다.
  • cache hit/miss와 재조회 트리거는 QA에서 설명 가능해야 한다.

9. Alternatives

대안 A. 화면별로 개별 최적화만 반복

  1. 장점: 당장 손보는 화면 하나는 빨리 개선할 수 있다.
  2. 단점: 동일한 실수를 다른 화면에서 반복하게 된다.
  3. 판단: 응급 처치로는 가능하지만 기준 아키텍처로 채택하지 않는다.

대안 B. DB read를 전면 polling + 앱 캐시로 흡수

  1. 장점: 구현이 단순해 보일 수 있다.
  2. 단점: 장기 비용과 stale state 리스크가 함께 커진다.
  3. 판단: 비용 최적화 방향으로 채택하지 않는다.

대안 C. 모든 read를 통합 RPC 하나로 수렴

  1. 장점: 왕복 횟수는 줄일 수 있다.
  2. 단점: 변경 결합도가 높아지고 hot/cold 분리 이점이 줄어든다.
  3. 판단: 필요한 영역에서 제한적으로만 검토한다.

10. Consequences / Impact

긍정 영향:

  1. 최적화 우선순위를 쿼리 수가 아니라 실제 hot path 비용 기준으로 정렬할 수 있다.
  2. 대시보드와 운영 화면에서 실시간닫힌 집계의 의미가 명확해진다.
  3. 동일 세션 내 중복 조회와 과도한 polling을 줄일 기준이 생긴다.

부정 영향 및 리스크:

  1. read class 분리 초기에 앱 상태 관리와 invalidation 규칙이 더 복잡해질 수 있다.
  2. 기존 ADR과 화면 문구 중 일부는 후속 정리가 필요하다.
  3. 계측 없이 캐시만 먼저 도입하면 잘못된 최적화가 될 수 있다.

11. Scope

  • 파트너 대시보드
  • 파트너 운영 및 편집
  • 사용자 근처 슬롯 탐색
  • 즐겨찾기 파트너 메타데이터
  • 구독 카탈로그 및 entitlement 조회

12. Validation

  • live currenthistorical snapshot의 용어가 UI와 문서에서 일관된다.
  • 대시보드 현황 용어가 전일 snapshot과 분리된다.
  • subscription_plans, subscription_addons가 파트너 전환 시 재조회되지 않는다.
  • 슬롯 목록 기본 조회 범위가 제한된다.
  • 근처 슬롯 polling 정책의 비용 예산이 문서화된다.
  • 화면별 read budget과 관측 항목이 QA 또는 운영 기준으로 연결된다.

13. Rollout / Migration

  1. 1차는 계측과 budget 정의를 먼저 적용한다.
  2. 2차는 파트너 운영 hot path와 정적 카탈로그 캐시를 정리한다.
  3. 3차는 대시보드 현황/전일/기간추이 의미 분리를 반영한다.
  4. 4차는 사용자 근처 슬롯과 즐겨찾기 메타데이터 조회를 줄인다.

14. Open Questions

  1. 사용자 근처 슬롯은 polling보다 이벤트 기반 무효화로 어느 정도까지 대체할 수 있는가.
  2. 파트너 운영 summary는 view가 적절한가, RPC가 적절한가.
  3. historical snapshot 캐시를 세션 캐시로 충분히 볼지, AsyncStorage까지 내릴지 추가 판단이 필요한가.