팩트 테이블
Fact Table
산출물
일어난 사건 하나를 한 줄로 쌓아 두는 표로, 금액이나 건수처럼 더할 수 있는 측정값을 담아 분석의 중심에 놓습니다.
등장 배경
"지난달 유료 전환이 몇 건이었나요" 같은 질문에 답하려면 원래는 여러 표를 이어 붙여야 했습니다. 결제 내역은 결제 시스템이 쌓는 표에, 계정이 언제 가입했는지는 가입 표에, 그 계정이 무슨 요금제를 쓰는지는 또 다른 표에 흩어져 있었습니다. 이 표들은 분석하라고 만든 것이 아니라 제품이 돌아가는 데 필요해서 만든 것이라, 어떤 칸이 어떤 칸과 짝인지 아는 사람만 답을 꺼낼 수 있었습니다.
그래서 주간 회의에는 같은 달 매출이 세 개씩 들어왔습니다. 한 사람은 환불을 뺐고, 한 사람은 결제일이 아니라 청구일로 끊었고, 한 사람은 체험 계정을 빼지 않았습니다. 각자의 방식으로는 다 맞았지만 한자리에 놓이면 아무 숫자도 쓸 수 없었고, 회의는 "숫자부터 맞춰 오자" 로 끝났습니다.
이 상황은 표의 생김새로 풉니다. 차원 모델링은 분석용 표를 측정값 쪽과 기준 쪽으로 갈라 설계하는데, 그중 측정값 쪽이 팩트 테이블입니다. 제품이 기록하기 편한 모양 대신 분석하는 사람이 묻기 편한 모양으로 다시 쌓아 두는 것이고, 그 표 하나를 모두가 같이 보면 매출이 세 개로 갈라지지 않습니다.
구성 항목
한 줄이 사건 하나에 대응하고, 칸은 세 종류로 나뉩니다.
- 키 칸 — 이 사건이 누구의 일이고 언제 일이며 어떤 상품에 대한 일인지를 가리키는 값입니다. 계정 번호, 요금제 번호, 날짜 번호 같은 것이 들어갑니다. 값 자체는 짧은 번호일 뿐이고, 그 번호가 가리키는 설명은 디멘전 테이블에 따로 있습니다.
- 측정값 칸 — 그 사건에서 실제로 잰 숫자입니다. 결제 금액 29,000원, 구매한 좌석 수 12개처럼 더할 수 있는 값입니다.
- 시각 칸 — 사건이 일어난 시점입니다. 날짜 키와 겹쳐 보이지만 키는 묶어 보기 위한 값이고 시각은 몇 시 몇 분인지를 남긴 값이라 둘 다 둡니다.
가장 먼저 정해야 하는 것은 그레인, 이 표에서 한 줄이 무엇 하나를 뜻하는지입니다. 결제 한 건이 한 줄인지, 한 계정의 하루치 합이 한 줄인지에 따라 같은 사건이 전혀 다른 개수로 쌓입니다. 적어 두지 않으면 나중에 누군가 하루치 합을 같은 표에 밀어 넣고, 그 표를 더한 매출은 실제의 두 배가 됩니다.
측정값 칸에는 더할 수 있는 값만 넣고, 전환율처럼 이미 나눗셈이 끝난 값은 넣지 않습니다. 3월 전환율 4퍼센트와 4월 2퍼센트를 평균 내면 3퍼센트지만, 두 달의 방문자 수가 다르면 합산 전환율은 3퍼센트가 아닙니다. 분자가 될 전환 건수와 분모가 될 방문 건수를 각각 칸으로 두고 꺼낼 때 나누면 어떤 기간으로 묶어도 값이 맞습니다.
작성자와 독자
만드는 사람은 데이터 엔지니어이고, 무엇을 담을지 정하는 사람은 그 표를 쓸 데이터 분석가입니다. 원천에서 값을 끌어와 매일 같은 시각에 쌓이게 만드는 일은 엔지니어의 몫이고, 한 줄을 무엇으로 셀지와 어떤 칸이 필요한지는 그 표로 답해야 하는 사람만 압니다.
표가 놓이는 자리도 정해져 있습니다. 원본을 손대지 않고 담아 두는 로우 레이어가 아니라 바로 꺼내 쓰도록 다듬어 둔 마트 레이어에 놓입니다. 원본은 틀린 규칙을 발견했을 때 돌아갈 자리라 그대로 두고, 팩트 테이블은 거기서 다시 계산합니다.
읽는 사람은 훨씬 넓지만 표를 직접 여는 사람은 분석가 몇 명뿐이고, 나머지는 대시보드나 주간 보고로 봅니다. 지현이 회의에서 부르는 지난주 유료 전환 건수도 화면에 뜬 숫자지만, 그 값이 어느 칸을 더한 것인지는 정해져 있습니다.
그래서 이 표에는 설명 문서가 따라붙습니다. 한 줄이 무엇인지, 각 칸이 어떤 규칙으로 계산되는지, 환불과 체험 계정은 어떻게 처리했는지를 적어 둡니다. 숫자의 뜻을 못 박는 지표 정의가 실제로 어느 칸에 구현돼 있는지를 잇는 역할입니다.
실무 용례
"그 숫자는 팩트 테이블에 칸이 없어서 지금은 못 뽑아요. 추가해도 다음 주부터 쌓입니다."
새 측정값은 칸을 만든 시점부터 채워지므로 지난 기간은 비어 있다는 뜻입니다.
"이 표 그레인이 결제 건이라서 계정별로 보려면 한 번 묶어야 해요."
한 계정이 여러 줄이라 계정 수를 세려면 중복을 먼저 걷어야 한다는 말입니다.
"그 매출은 팩트 테이블에서 바로 나온 값이에요. 각자 계산한 게 아닙니다."
출처가 합의된 표 하나라 다른 회의의 숫자와 어긋나지 않는다는 뜻입니다.
페이지덱에서 이 표는 요금제별 매출을 보려던 요청에서 시작됐습니다. 지현이 "요금제를 바꾼 뒤로 팀 플랜 매출이 늘었는지" 를 묻자 태오가 결제 시스템 표를 열어 봤는데, 거기에는 요금제 이름이 없고 상품 코드만 있었습니다. 코드와 이름을 잇는 표는 다른 팀이 관리했고 이름이 바뀐 적도 있어서, 6개월 전 결제 건의 요금제가 조회할 때마다 다르게 보였습니다.
그래서 결제 한 건을 한 줄로 두고 계정 번호와 요금제 번호와 금액만 남긴 표를 새로 만들고, 요금제 이름은 디멘전 테이블로 옮겼습니다. 이제 지현은 대시보드에서 요금제로 묶은 매출을 바로 보고, 태오는 이름이 바뀌어도 팩트 테이블은 한 줄도 고치지 않습니다.
흔한 오해
이름 때문에 팩트 테이블을 원본 기록 자체로 오해하는 경우가 많습니다. 사실이라는 말이 붙어 있으니 손대지 않은 원천으로 읽기 쉽습니다. 하지만 이 표는 그레인과 칸을 사람이 정해서 다시 쌓은 가공물입니다. 원본에 있던 칸 중 분석에 쓰지 않는 것은 빠지고, 환불 처리나 체험 계정 제외 규칙도 이미 적용돼 있습니다. 원본이라고 믿고 쓰면 "결제 시스템에 있는 이 칸이 왜 여기 없냐" 는 요청이 끝없이 들어오고, 요청을 받는 대로 칸을 붙이다 보면 아무도 전체를 설명하지 못하는 표가 됩니다.
칸이 많을수록 좋은 표라고 생각하는 것도 흔합니다. 한 표에 다 있으면 편해 보이니 그렇습니다. 그런데 요금제 이름처럼 설명에 해당하는 값을 직접 넣으면 두 가지가 무너집니다. 결제가 수천만 건 쌓이는 표에 긴 글자 칸이 붙으면 조회가 눈에 띄게 느려지고, 요금제 이름이 바뀔 때마다 과거 줄을 전부 찾아 고쳐야 하고 한 번 빠뜨리면 같은 요금제가 두 이름으로 갈립니다. 설명을 디멘전 테이블에 한 줄로 두면 이름을 고칠 자리가 한 곳으로 줄어듭니다.
자주 헷갈리는 용어
| 용어 | 한 줄이 무엇인가 | 팩트 테이블과의 차이 |
|---|---|---|
| 디멘전 테이블 | 계정·요금제·날짜 같은 대상 하나 | 값이 바뀌면 그 줄을 고칩니다. 팩트 테이블은 줄을 고치지 않고 계속 쌓기만 하므로 시간이 지나면 수백 배 커집니다 |
같이 보면 좋은 페이지
- 분석용 데이터 저장소
이 표가 어떤 그릇의 어느 층에 놓이는지 전체 지형을 봅니다
- 차원 모델링
팩트 테이블과 디멘전 테이블로 나누는 설계 방법 전체를 봅니다
마지막 업데이트 2026-09-16