[Snowflake 101] Day 5: NoSQL은 필요 없다, 반정형 데이터와 Variant
현대 데이터 엔지니어링에서 가장 골치 아픈 존재는 JSON, XML, Avro 같은 반정형 데이터(Semi-structured Data)다.
애플리케이션 로그, 모바일 이벤트, 외부 API 응답은 대부분 JSON 형태다. 과거에는 이를 분석하기 위해 두 가지 방법 중 하나를 택했다.
- Hadoop이나 MongoDB 같은 별도의 NoSQL 저장소를 구축한다. (시스템 복잡도 증가)
- ETL 과정에서 파서(Parser)를 짜서 RDBMS 테이블 스키마에 맞춰 억지로 펴 넣는다. (스키마 변경 시 대응 불가)
Snowflake는 VARIANT라는 데이터 타입을 통해 이 문제를 해결한다. JSON을 그대로 로드하고, 표준 SQL로 조회한다. 별도의 NoSQL DB는 필요 없다.
1. Schema-on-Read: 일단 넣고 나중에 정의한다
Snowflake에서는 테이블 스키마를 미리 정의할 필요 없이 JSON 데이터를 통째로 넣을 수 있다. 이를 Schema-on-Read 방식이라고 한다.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
-- 테이블 생성 (단 하나의 컬럼만 있으면 된다)
CREATE TABLE raw_events (
src VARIANT
);
-- JSON 데이터 적재 예시
INSERT INTO raw_events
SELECT PARSE_JSON('{
"event_type": "click",
"user": {
"id": 101,
"name": "Jane",
"preferences": ["dark_mode", "beta_tester"]
},
"timestamp": 1704067200
}');
VARIANT 타입은 단순한 텍스트 저장(String)이 아니다. Snowflake는 내부적으로 JSON의 구조를 파악하여, 데이터를 압축하고 바이너리 형태로 최적화해 저장한다.
2. 직관적인 JSON 쿼리
저장된 JSON 데이터를 조회할 때는 콜론(:) 표기법을 사용한다. 계층 구조가 깊어도 점(.)을 찍어서 접근할 수 있다.
1
2
3
4
5
6
7
8
SELECT
src:event_type::string AS event_type,
src:user.id::int AS user_id,
src:user.name::string AS user_name,
src:timestamp::timestamp AS event_time
FROM raw_events
WHERE src:event_type = 'click';
- 경로 탐색:
컬럼명:키이름.하위키형태로 접근한다. - 타입 캐스팅:
::타입(예:::string,::int)을 붙여 SQL 데이터 타입으로 변환한다. 이를 붙이지 않으면 따옴표가 포함된 JSON 값이 반환된다.
3. 배열(Array) 다루기: FLATTEN
JSON 안에 배열([])이 있는 경우, 이를 여러 개의 행(Row)으로 펼쳐야 할 때가 있다. 이때 LATERAL FLATTEN 구문을 사용한다.
위 예시 데이터에서 preferences 배열을 펼쳐보자.
1
2
3
4
5
6
SELECT
src:user.name::string AS user_name,
value::string AS preference
FROM raw_events,
LATERAL FLATTEN(input => src:user.preferences);
결과:
| user_name | preference |
|---|---|
| Jane | dark_mode |
| Jane | beta_tester |
Join 문법 없이 쉼표(,)와 LATERAL FLATTEN만으로 비정규화된 데이터를 정규화된 테이블 형태로 변환할 수 있다.
4. 성능의 비밀: 자동 컬럼화
“JSON을 쿼리하면 풀 스캔(Full Scan) 때문에 느리지 않나?”
Snowflake는 영리하다. VARIANT 컬럼에 데이터가 들어오면, 백그라운드 프로세스가 자주 사용되는 경로(Key)를 감지하여 내부적으로 별도의 컬럼처럼 추출해 저장한다.
사용자가 src:user.id를 조회할 때, Snowflake는 JSON 전체를 뒤지는 것이 아니라 내부적으로 추출된 user.id 컬럼 데이터만 읽는다. 덕분에 정형 데이터 테이블을 조회하는 것과 거의 동일한 성능을 낸다.
Series Wrap-up
5일간 Snowflake의 핵심 기능을 훑어보았다.
1
2
3
4
5
6
7
8
9
Day 1 (Architecture): Storage와 Compute의 분리로 무한한 확장성을 얻었다.
Day 2 (Warehouse): 필요할 때 켜고 끄며 비용과 성능을 제어한다.
Day 3 (Time Travel): 백업 없이도 과거 데이터를 즉시 조회하고 복구한다.
Day 4 (Cloning): 운영 데이터를 비용 없이 복제해 개발 환경을 만든다.
Day 5 (Variant): 정형 데이터와 반정형 데이터를 한 곳에서 처리한다.
Snowflake는 단순한 데이터 웨어하우스가 아니다. Data Lake의 유연성과 Data Warehouse의 관리 용이성을 합친 ‘Data Cloud’다. 이 도구를 얼마나 잘 활용하느냐에 따라 데이터 팀의 생산성은 극적으로 달라질 수 있다.