576. 팩트리스 팩트 테이블 (Factless Fact Table) 모델

⚠️ 이 문서는 데이터 웨어하우스(DW)의 중심이 되는 팩트 테이블(Fact Table)이 무조건 '매출액', '클릭 수' 같은 '숫자(측정값)'를 가져야 한다는 고정관념을 깨고, **숫자(Fact)는 하나도 없이 오직 차원 테이블(Dimension)들을 이어주는 외래 키(Foreign Key)들만으로 구성되어, "학생이 이 수업에 출석했다" 또는 "이벤트가 발생했다"는 사실(Event) 그 자체를 추적하고 분석하기 위해 고안된 '팩트리스 팩트 테이블'**을 다룹니다.

핵심 인사이트 (3줄 요약)

  1. 본질: 이름 그대로 '팩트(숫자)'가 없는 '팩트 테이블'이다. 오직 [날짜_Key], [학생_Key], [과목_Key] 같이 누가, 언제, 무엇을 했는지를 나타내는 외래 키(FK)들의 조합만으로 이루어져 있다.
  2. 가치: "매출은 없지만 어떤 사건이 일어났다"는 사실을 기록한다. 대학교의 수강 신청, 병원의 진료 예약, 웹사이트의 프로모션 팝업 노출 등 돈(숫자)으로 환산되지 않는 다대다(M:N) 관계의 이벤트를 카운트(COUNT) 분석할 때 절대적인 역할을 한다.
  3. 기술 체계: 사건의 발생 여부를 기록하는 이벤트 추적(Event Tracking) 모델과, 특정 프로모션 기간에 어떤 상품이 세일 중이었는지를 보여주는 커버리지(Coverage/Conditions) 모델 두 가지 형태로 활용된다.

Ⅰ. 팩트(숫자)가 없는 팩트 테이블의 모순

모든 비즈니스 활동에 '수량'과 '금액'이 존재하는 것은 아니다.

  1. 전통적 팩트 테이블의 공식:
    • 일반적인 스타 스키마(Star Schema)에서 팩트 테이블은 [날짜_Key], [고객_Key], [상품_Key] 옆에 반드시 [판매_수량], [매출_금액] 같은 더하기, 빼기가 가능한 측정값(Measure)이 있어야 한다.
  2. 숫자가 없는 비즈니스 이벤트:
    • 대학교의 '출석부' 시스템을 생각해 보자.
    • 홍길동 학생이 10월 1일에 데이터베이스 수업에 출석했다. 이 사건에는 판매 수량도, 매출액도 없다. 그냥 "홍길동, 10월 1일, DB수업"이라는 3개의 차원(Dimension) 키값만 존재할 뿐이다.
  3. 팩트리스 팩트 테이블의 탄생:
    • 랄프 킴볼은 이 3개의 키값만 묶어서 하나의 팩트 테이블을 만들었다.
    • 숫자는 없지만, 이 테이블의 줄(Row) 개수를 COUNT() 함수로 세기만 하면 "홍길동의 한 달 총 출석 일수"라는 엄청나게 가치 있는 분석 통계를 즉시 뽑아낼 수 있게 된다. 이것이 팩트리스 팩트 테이블의 본질이다.

📢 섹션 요약 비유: 쇼핑몰 영수증(일반 팩트 테이블)에는 "사과 3개, 3,000원"이라는 명확한 숫자가 찍혀 있습니다. 하지만 대학교 출석부(팩트리스 팩트 테이블)에는 가격이나 개수가 없습니다. 그저 "홍길동, O월 O일, 출석"이라는 동그라미(이벤트 발생) 흔적만 있습니다. 숫자는 없지만 이 동그라미의 개수를 나중에 세어보면(COUNT), 학생의 성실함이라는 엄청난 통계적 지표를 뽑아낼 수 있는 특수 장부입니다.


Ⅱ. 두 가지 활용 패턴: 이벤트(Event)와 커버리지(Coverage)

단순한 카운트를 넘어서, '일어나지 않은 일'까지 추적한다.

  1. 이벤트 추적 (Event Tracking) 모델:
    • 가장 흔한 형태다. 앞서 말한 대학 수강 신청이나 출석부처럼 특정 사건이 "발생했다"는 1회성 사실을 기록한다.
    • 예: 웹사이트에서 고객이 광고 배너를 클릭했다. ([고객_Key], [배너_Key], [시간_Key]) $\rightarrow$ "A 고객이 이 배너를 총 몇 번 눌렀는가?"를 카운트할 수 있다.
  2. 커버리지 (Coverage/Conditions) 모델:
    • 이 모델은 사건의 발생이 아니라, **"어떤 조건이나 환경이 세팅되어 있었다"**는 것을 기록한다.
    • 예: 이마트에서 1주일 동안 '봄맞이 할인 행사'를 했다. 이 행사에는 100개의 상품이 포함되었다.
    • 팩트리스 테이블에 [행사_Key], [상품_Key], [할인율_Key]를 기록해 둔다.
  3. '일어나지 않은 일(What did NOT happen)'의 발견:
    • 커버리지 모델의 진짜 위력은 여기에 있다. 사장님이 묻는다. "봄맞이 행사 상품 100개 중에서, 행사 기간 동안 단 한 개도 안 팔린(매출 0원) 악성 재고 상품이 뭐야?"
    • '실제 판매 팩트 테이블(팔린 것만 기록)'에는 안 팔린 상품 기록이 없다. 하지만 '행사 커버리지 팩트리스 테이블(세팅된 상품 100개 기록)'과 대조(Minus Join)해 보면, 100개 중 안 팔린 상품 리스트를 귀신같이 찾아낼 수 있다.

📢 섹션 요약 비유: 백화점에서 전단지를 뿌렸습니다. 전단지에 실린 100개의 할인 상품 목록(커버리지 팩트리스 테이블)을 장부에 적어둡니다. 오늘 팔린 물건 영수증(판매 팩트 테이블)을 가져와 전단지 목록과 대조해 봅니다. 영수증에 없는 전단지 상품을 색출하면, "아, 이 상품은 전단지에 대문짝만하게 할인한다고 홍보(세팅)를 했는데도 손님들이 거들떠보지도 않은(일어나지 않은 일) 쓰레기 상품이구나!"라고 뼈 때리는 분석을 해낼 수 있습니다.


Ⅲ. 설계 시 주의점과 더미(Dummy) 팩트의 유혹

숫자가 없다고 억지로 숫자 1을 넣으면 하수가 된다.

  1. 더미 팩트 (Dummy Fact = 1)의 불필요성:
    • 초보 데이터 엔지니어들은 팩트 테이블에 숫자가 없으면 왠지 허전해서, [출석_건수]라는 컬럼을 만들고 무조건 숫자 1을 하드코딩해서 박아 넣는 실수를 한다. 나중에 SUM(출석_건수)를 하려고 말이다.
    • 랄프 킴볼은 이를 강력히 비판했다. RDBMS에서는 COUNT(*) 연산이 이미 충분히 빠르며, 무의미한 숫자 1을 수억 개의 행(Row)에 저장하는 것은 엄청난 디스크 공간의 낭비일 뿐이다.
  2. 외래 키(FK) 인덱스 최적화:
    • 팩트리스 테이블은 측정값이 없고 오직 외래 키(FK) 3~4개로만 이루어져 있으므로, 이 키들의 조합이 곧 고유한 기본 키(Primary Key) 역할을 한다.
    • 검색을 극도로 빠르게 하기 위해, 이 외래 키들의 묶음을 비트맵 인덱스(Bitmap Index)나 복합 인덱스로 꽉 묶어두는 것이 쿼리 성능(COUNT 등)을 10배 이상 끌어올리는 설계의 핵심이다.

📢 섹션 요약 비유: 출석부에 출석을 부를 때, 굳이 학생 이름 옆에 "출석 횟수: 1번"이라고 매일 똑같은 숫자를 반복해서 볼펜으로 적어 넣는 것(더미 팩트)은 바보 짓입니다. 잉크 낭비일 뿐입니다. 훌륭한 선생님은 그냥 날짜와 이름에 동그라미만 쳐두고, 나중에 월말에 그 동그라미의 개수를 눈으로 쓱 세어보는(COUNT) 것만으로도 완벽하고 공간 효율적인 출석부 관리를 해냅니다.