[TIL] 스냅샷(Snapshot)에 대한 이해

김재진·2026년 2월 5일

내일배움캠프

목록 보기
48/70

학습배경

커머스 시스템을 설계하던 중, "상품 가격이 변동되면 과거의 주문 내역은 어떻게 유지되는가?"라는 문제에 직면함. 이를 해결하기 위한 데이터 보존 방식인 스냅샷 패턴을 학습함.


1. 스냅샷(Snapshot)이란?

데이터베이스 설계에서 특정 시점의 상태를 그대로 복사하여 저장하는 방식을 의미함. 보통 DB 정규화는 중복을 피하기 위해 ID(외래키)만 저장하는 것을 권장하지만, 결제와 같은 증빙이 필요한 도메인에서는 당시의 데이터를 중복 저장하는 비정규화 방식인 스냅샷이 필수적임.


2. 참조 방식 vs 스냅샷 방식 비교

참조 방식 (Foreign Key Only)

  • 구조: OrderItem 테이블이 Product 테이블의 id만 가짐.
  • 문제점: 상품 테이블의 가격이 수정되면, 과거의 모든 주문 내역서 가격이 함께 변함 (매출 데이터 왜곡).

스냅샷 방식 (Data Copying)

  • 구조: OrderItem 테이블이 id뿐만 아니라 price, name 컬럼을 직접 가짐.
  • 장점: 원본 상품 데이터가 삭제되거나 수정되어도 결제 당시의 정보를 완벽하게 보존함.

3. 스냅샷 사용 예시

  1. PM 12:00: '기계식 키보드' 가격이 이벤트로 15만원 → 10만원으로 변경됨.
  2. PM 12:05: 고객 A가 10만원에 주문 완료.
  3. PM 13:00: 이벤트 종료 후 가격이 다시 15만원으로 환원됨.

결과:

  • 참조 방식: 고객 A의 주문 상세 페이지에 "15만원"으로 표시됨 (CS 발생).
  • 스냅샷 방식: OrderItem 테이블의 price 컬럼에 "100,000"이 기록되어 있어 가격 변동에 영향을 받지 않음.

4. 백엔드 구현 핵심 로직 (Pseudo Code)

public void createOrder(Long productId, int quantity) {
    // 1. 현재 시점의 상품 정보를 조회 (Source)
    Product product = productRepository.findById(productId);
    
    // 2. 주문 상세 객체를 생성할 때 '현재 가격'을 스냅샷으로 저장
    OrderItem orderItem = OrderItem.builder()
        .productId(product.getId())
        .orderPrice(product.getPrice()) // 이 시점의 가격을 박제!
        .productName(product.getName()) // 이 시점의 상품명을 박제!
        .quantity(quantity)
        .build();
    
    // 3. 주문 저장
    orderRepository.save(new Order(orderItem));
}

5. 마무리

  • "데이터베이스의 정규화가 항상 정답은 아니다." 비즈니스의 성격에 따라서는 데이터의 중복을 허용하더라도 불변성을 유지하는 것이 훨씬 중요하다는 것을 깨달음.
profile
개발공부 처음해보는 사람

0개의 댓글