LabHub

데이터 파이프라인 · 스키마와 포맷 · 이론

스키마 — 검증하지 않으면 나중에 두 배로 낸다

LabHub 에서 이어서 보기

한 줄 요약

외부에서 들어오는 데이터는 전부 문자열이라고 가정하고 시작해, 명시적으로 검증하고 변환한 뒤에만 타입 있는 표에 넣어야 한다.

왜 이게 필요했나

실무의 원본 데이터는 예외 없이 지저분하다. 같은 날짜가 네 가지 형식으로 들어오고, 금액에는 통화 기호와 천 단위 쉼표가 붙어 있으며, 상태값은 대소문자와 앞뒤 공백이 제각각이고, 필수 항목이 비어 있다.

이것을 그대로 타입 있는 표에 넣으려 하면 적재가 실패한다. 그러면 흔히 두 가지 잘못된 대응이 나온다. 실패한 행을 그냥 건너뛰거나(아무도 모르게 데이터가 사라진다), 모든 컬럼을 텍스트로 만들어 버리는 것이다(문제를 하류로 미룬다).

어떻게 동작하나

표준적인 구조는 세 층이다.

1. 원본(staging) — 모든 컬럼이 문자열. 있는 그대로 보관한다. 절대 고치지 않는다.
2. 정제(clean) — 검증을 통과한 행만 타입을 갖춘 채로 들어간다.
3. 거부(reject) — 통과하지 못한 행과 그 이유가 들어간다.

이 구조의 핵심은 보존 법칙이다. 정제 건수와 거부 건수의 합이 원본 건수와 정확히 같아야 한다. 어느 쪽에도 없는 행이 있다면 그것은 조용히 사라진 데이터이고, 파이프라인에서 가장 위험한 사고다.

거부 사유를 남기는 것도 타협할 수 없다. 사유 없이 버린 행은 나중에 아무도 복구하지 못한다. "amount 없음", "email 없음" 처럼 짧아도 좋으니 반드시 함께 적는다.

변환 규칙도 명시적이어야 한다. 날짜 형식이 여러 개라면 각 형식을 정규식으로 판별해 서로 다른 파싱 규칙을 적용한다. 자동 추론에 맡기면 03/04/2025 가 3월 4일인지 4월 3일인지에 따라 조용히 틀린다.

금액에서 빈 문자열을 0 으로 바꾸는 것도 흔한 실수다. 값이 없는 것과 0 은 다르다. 결제 금액이 비어 있다면 그것은 0원 결제가 아니라 정보 누락이며, 0 으로 채우는 순간 그 사실이 지워진다.

현장에서 만나는 모습

스키마 계약을 코드로 남기는 것이 도움이 된다. 정제 표의 컬럼과 타입 목록을 별도 표에 기록해 두면, 나중에 누군가 컬럼 타입을 바꿨을 때 하류 파이프라인이 즉시 감지할 수 있다. 스키마 변경은 원래 조용히 일어나서 며칠 뒤에 이상한 숫자로 드러나는 부류의 사고다.

포맷 선택도 짚어 둘 만하다. CSV 는 어디서나 읽히지만 타입 정보가 없고 구분자 이스케이프가 취약하다. JSON 은 중첩을 표현하지만 부피가 크다. Parquet 같은 컬럼 지향 포맷은 타입과 통계를 함께 담고 압축률이 좋아 분석 워크로드에 유리하다. 원본 보관은 CSV 나 JSON 으로, 분석용 재적재는 컬럼 포맷으로 나누는 구성이 흔하다.

다음 실습에서 할 것

문자열로만 이루어진 staging.orders_raw 를 프로파일링해 결함을 세고, 날짜와 금액과 상태를 정규화한 뒤, 정제 표와 거부 표로 나눠 적재하고 보존 법칙이 성립하는지 확인한다.