[DuckDB] Intro Roadmap and some Reading


DuckDB

DuckDB Intro - Roadmap and some Reading

Created: September 2, 2026 3:35 PM Class: DuckDB

DuckDB 학습 로드맵

학습 원칙: 문서는 순서대로 완독하지 않는다. 아래 단계 순서대로 필요한 페이지만 골라 읽고, 읽자마자 .duckdb 가상환경에서 바로 실행한다.


1단계 — 개념 이해 (반나절)

  • 왜 배우는가: In-process OLAP 엔진, “분석가용 SQLite” 포지셔닝
  • 문서: Why DuckDB

2단계 — Python 클라이언트 기본 (10~15분, 얇게)

  • duckdb.connect(), con.sql(), .df() — 연결/실행/결과 반환 방식만
  • 문서: clients/python/overview (여기서 SQL 문법까지 배우려 하지 말 것 — 얕게 훑기)

3단계 — SQL 문법 차이 (2~3일)

표준 SQL과 다른, DuckDB 고유 편의 문법 위주:

| 기능 | 용도 | | — | — | | SELECT * EXCLUDE / REPLACE | 특정 컬럼만 빼거나 변형해서 조회 | | GROUP BY ALL / ORDER BY ALL | 자동 그룹핑/정렬 | | QUALIFY | 윈도우 함수 결과 필터링 | | PIVOT / UNPIVOT | 엑셀식 피벗 |

  • 문서: sql/Friendly SQL

4단계 — 파일 직접 쿼리 (2일)

  • 테이블 로드 없이 CSV/Parquet를 바로 FROM 'file.parquet'로 쿼리
  • Parquet 우선순위로 학습 (실무에서 CSV보다 압도적으로 많이 씀)
  • 문서: data/parquet, data/csv

5단계 — 중첩 데이터: UNNEST / STRUCT (GA4 대비 최우선 ★)

  • GA4 BigQuery 익스포트의 event_params, items가 STRUCT 배열 형태라, 이 문법이 가장 레버리지 높은 학습 지점
SELECT event_name, ep.key, ep.value.string_value
FROM events, UNNEST(event_params) AS ep;  -- 배열을 행으로 펼침
  • 문서: sql/data_types/nested, sql/query_syntax/unnest

6단계 — 성능 감각 (1일)

  • 컬럼 지향 + 벡터화 실행, Parquet 통계 기반 프루닝, 자동 멀티스레드
  • “왜 이 쿼리가 느린가”를 판단할 최소한의 내부 구조 이해

7단계 — 실무 연동

  • pandas 연동: SELECT * FROM df 형태로 DataFrame 직접 쿼리
  • 비용 절감 워크플로우: BigQuery에서 샘플을 Parquet로 내려받아 DuckDB로 쿼리를 빠르게 반복 검증 → 완성된 쿼리만 BigQuery에 실행 (스캔 비용 절감)
  • dbt-duckdb: 이름과 동작 원리 정도 이해 (로컬 dbt 개발 환경으로 흔히 쓰임)

8단계 — 실습

  • NYC Taxi 데이터셋(Parquet)으로 3~6단계 문법 종합 연습
  • GA4 스키마를 흉내낸 샘플 데이터로 UNNEST 실전 연습

예상 소요: 집중 시 1.5~2주. 5단계(UNNEST/STRUCT)에 시간을 가장 많이 배분하시길 권합니다.


Dissertation Reading

“One Size Fits All”: An Idea Whose Time Has Come and Gone

논문 개요

  • 제목: “One Size Fits All”: An Idea Whose Time Has Come and Gone
  • 저자: Michael Stonebraker (MIT, INGRES/Postgres 설계자), Uğur Çetintemel (Brown University)
  • 학회: ICDE 2005 (사용하신 파일명은 2015로 돼있지만 논문 본문 기준 실제 발표는 2005년입니다)
  • 위상: DB 시스템 역사에서 자주 인용되는 포지션 페이퍼입니다. DuckDB, ClickHouse, Snowflake 같은 컬럼 지향 분석 엔진들이 등장하게 된 사상적 배경이 되는 논문이라, 지금 학습 중인 DuckDB와 직접 연결됩니다.

핵심 주장 (Thesis)

“하나의 DBMS 아키텍처로 모든 워크로드를 처리한다”는 지난 25년간의 업계 전략이 더 이상 통하지 않으며, 시장은 워크로드별 특화 엔진들로 분화될 것이다.

저자들은 이 전략이 유지된 이유가 기술적 우월성이 아니라 영업/마케팅/유지보수 비용 문제였다고 지적합니다 (코드라인이 여러 개면 유지보수비 증가, 영업 혼란, 포지셔닝 문제). 즉 “One size fits all”은 애초에 성능 최적화가 아니라 비즈니스 편의를 위한 선택이었다는 게 논지의 출발점입니다.


근거 1: 데이터 웨어하우징 (OLTP vs OLAP)

SQLD 범위에서 익숙하실 정규화/인덱스 개념을 확장해서 이해하시면 됩니다.

  • OLTP는 쓰기(update) 최적화, 웨어하우스는 읽기(ad-hoc 쿼리) 최적화라는 근본적으로 다른 워크로드입니다.
  • 스키마 차이: 웨어하우스는 스타 스키마(fact table + dimension table)가 표준인데, OLTP에서는 이런 구조가 거의 안 쓰입니다.
  • 인덱스 차이: OLTP는 B-tree, 웨어하우스는 비트맵 인덱스가 유리 — 이유는 웨어하우스가 소수 컬럼에 대한 대량 집계가 많기 때문.
  • 핵심 기술 포인트 (5.1절): 저장 방식 자체가 다릅니다.
    • Row-store(행 지향): 레코드 하나를 디스크에 한 번에 쓰기 좋음 → OLTP에 적합
    • Column-store(열 지향): 쿼리에 필요한 컬럼만 읽으면 되므로 대량 집계에 압도적으로 유리 → 웨어하우스에 적합
    • 바로 이 column-store 아이디어가 DuckDB의 핵심 아키텍처입니다. 지난 대화에서 설명드린 “컬럼 지향 + 벡터화 실행”이 이 논문에서 이미 예견된 방향입니다.

근거 2: 스트림 처리 (논문의 메인 실험, 3~4절)

가장 구체적인 성능 데이터가 나오는 부분입니다.

실험 설계

  • 금융 피드 지연 알림 애플리케이션(주식 시세 지연 감지)을 StreamBase(전문 스트림 처리 엔진)와 상용 RDBMS로 각각 구현해 처리량 비교
  • 4500개 종목 (500개 빠른 종목: 5초 지연 기준 / 4000개 느린 종목: 60초 지연 기준), 2개 피드 제공사

결과

  • StreamBase: 초당 160,000 메시지 처리
  • RDBMS: 초당 900 메시지 처리
  • 약 178배(두 자릿수, 논문 표현으로는 “two orders of magnitude”) 성능 차이

이 차이의 4가지 원인 (4.1~4.5절) — 논문의 실질적 핵심

  1. Inbound vs Outbound 처리 모델: RDBMS는 “저장 후 조회”(outbound, pull 방식)가 기본 설계인데, 스트림 처리는 “데이터가 흐르면서 즉시 처리”(inbound, push 방식)가 필요. RDBMS의 트리거는 이를 흉내내려는 “덧붙인 기능”일 뿐이라 근본적으로 느림.
  2. 적합한 프리미티브의 부재: SQL의 GROUP BY는 “테이블의 끝”을 전제로 하는데, 스트림은 끝이 없음. 스트림 엔진은 시간 윈도우(sliding window) 개념을 기본 내장하지만 RDBMS는 이를 SQL로 흉내내야 해서 비효율적.
  3. DBMS 처리와 애플리케이션 로직의 통합: RDBMS는 보안을 위해 클라이언트-서버 구조(별도 주소 공간)로 설계됐지만, 스트림 처리는 신뢰된 단일 애플리케이션이므로 같은 프로세스 안에서 DB 로직과 앱 로직을 섞는 게 프로세스 전환(context switch) 비용을 없애 훨씬 빠름.
  4. 고가용성(HA)과 동기화: 로그 기반 복구는 스트림 환경에 부적합(다운타임 발생), ACID 트랜잭션도 대부분의 스트림 앱엔 과한 스펙(단일 사용자 환경이라 세마포어 수준의 가벼운 동기화로 충분).

근거 3: 그 외 특화 시장 (5절, 짧게 언급)

  • 센서 네트워크: 전력/대역폭이 핵심 제약이라 기존 DBMS 최적화 전략 자체가 무의미
  • 텍스트 검색: Google이 자체 GFS를 만든 사례 — append-only 쓰기, 순차 읽기, 장애 상시 발생을 전제로 한 아키텍처가 필요해 RDBMS로는 부적합
  • 과학 데이터베이스: 다차원 인덱싱, 데이터 계보(lineage) 추적 등 특수 요구
  • XML 데이터베이스: 관계형 모델에 잘 안 맞는 반정형 데이터 — 확장이냐 별도 엔진이냐 논쟁 중이라고만 언급 (결론 없이 open question으로 남김)

결론 (7절)

앞으로 도메인별 특화 DB 엔진들이 다수 등장할 것이며, “One size fits all”은 더 이상 지속 가능한 전략이 아니다 — 라는 예측으로 마무리됩니다. 저자들 스스로 “흥미로운 시대가 올 것”이라며 다소 낙관적/도발적인 톤으로 끝맺습니다.


왜 지금 이 논문이 의미 있는가

이 논문이 2005년에 예측한 흐름이 이후 20년간 그대로 실현됐습니다:

  • 웨어하우스 → 컬럼 스토어 (Vertica, Snowflake, BigQuery, DuckDB)
  • 스트림 처리 → Kafka Streams, Flink
  • 텍스트 검색 → Elasticsearch
  • NoSQL/문서 DB → MongoDB 등 (XML 논쟁의 후신)

DuckDB는 정확히 이 논문의 5.1절(column-store)이 예견한 방향의 산물입니다 — “분석 워크로드는 row-store RDBMS로는 한계가 있다”는 이 논문의 주장이, 20년 뒤 “로컬 환경에서도 쓸 수 있는 임베디드 column-store”라는 형태로 구현된 게 DuckDB라고 보시면 됩니다. 앞서 배우신 “왜 DuckDB가 컬럼 지향이라 빠른가”의 이론적 뿌리가 바로 이 논문입니다.


Everything You Always Wanted to Know About Compiled and Vectorized Queries But Were Afraid to Ask

논문 개요

  • 제목: Everything You Always Wanted to Know About Compiled and Vectorized Queries But Were Afraid to Ask
  • 저자: Timo Kersten, Viktor Leis, Alfons Kemper, Thomas Neumann (TU München), Andrew Pavlo (CMU), Peter Boncz (CWI)
  • 학회: VLDB 2018, Vol. 11
  • 중요 포인트: 공저자 Peter Boncz는 DuckDB의 공동 창시자이자, 이 논문이 다루는 “vectorized execution” 패러다임을 처음 제안한 MonetDB/X100 연구의 원저자입니다. 즉 이 논문은 DuckDB가 왜 지금의 실행 엔진 구조를 택했는지에 대한 이론적·실험적 근거 그 자체입니다.

배경: 두 가지 경쟁 패러다임

SQLD 수준에서는 “쿼리 옵티마이저가 실행 계획을 짠다”까지만 다루지만, 이 논문은 그 실행 계획을 실제로 어떻게 실행하느냐 — 즉 DB 엔진의 CPU 레벨 구현 방식을 다룹니다. 기존의 Volcano 스타일(한 번에 한 행씩 처리)은 요즘 CPU에서 비효율적이라는 전제 아래, 현대 OLAP 엔진들은 두 방식 중 하나를 씁니다.

방식대표 시스템핵심 아이디어
Vectorized (벡터화)MonetDB/X100 → VectorWise → DuckDB한 번에 한 행이 아니라, ~1000개 단위의 배치(vector)로 처리. 각 연산은 하나의 자료형에 특화된 단순 함수(“primitive”)로 쪼개짐
Data-centric Compilation (컴파일)HyPer, Peloton쿼리마다 전용 머신코드를 생성해서, 파이프라인 전체를 하나의 타이트한 루프로 융합. 중간값을 CPU 레지스터에 그대로 유지

실험 방법론

기존 비교 연구들은 HyPer vs VectorWise처럼 실제 상용 시스템끼리 비교했는데, 문제는 두 시스템이 실행 모델 외에도 압축 방식, 병렬화 전략, 최적화기 등 너무 많은 부분이 달라서 “실행 모델 자체”의 차이를 순수하게 볼 수 없었습니다.

  • 그래서 저자들은 동일한 알고리즘·자료구조를 쓰는 두 엔진을 직접 구현합니다: 컴파일 방식 “Typer”, 벡터화 방식 “Tectorwise”
  • 실행 모델 하나만 다르게 두고 나머지는 통제 → apples-to-apples 비교
  • TPC-H 벤치마크 중 5개 쿼리를 대표로 선정 (산술 집계, 선택적 필터, 조인 2종, 고카디널리티 집계)

핵심 발견

1. 전반적으로는 막상막하

두 모델의 성능 차이는 크지 않습니다 (Q1에서 컴파일이 74% 빠름 ~ Q9에서 벡터화가 32% 빠름 수준). 참고로 HyPer와 PostgreSQL의 차이는 10~100배인 것과 비교하면, 두 최신 패러다임 사이의 격차는 미미한 수준입니다.

2. 컴파일이 유리한 경우: 연산이 많은 쿼리

Typer(컴파일)는 중간 계산값을 CPU 레지스터에 그대로 들고 있을 수 있어서, 벡터화보다 실행 명령어 수 자체가 적습니다(최대 2.4배 적음). Q1처럼 산술 연산이 지배적인 쿼리에서 압도적으로 유리한 이유입니다.

3. 벡터화가 유리한 경우: 조인처럼 메모리 접근이 많은 쿼리

직관과 달리, 벡터화는 명령어 수는 더 많이 실행하는데도 해시 조인 같은 작업에서는 더 빠릅니다. 이유는:

  • 벡터화 코드는 루프가 단순해서, CPU의 비순차 실행(out-of-order execution) 엔진이 더 많은 메모리 요청을 미리 동시에 던질 수 있음
  • 캐시 미스로 인한 대기 시간(memory stall)을 더 잘 숨김
  • 컴파일 코드는 한 루프 안에 스캔+필터+조인+집계가 다 섞여있어서 이 “선행 요청”의 여지가 줄어듦

SQLD에서 인덱스/조인 성능을 “논리적 비용”으로만 배우셨다면, 이 부분이 그 아래 물리적 계층(CPU 캐시, 메모리 지연시간)에서 실제로 무슨 일이 벌어지는지를 보여주는 대목입니다.

4. SIMD(하나의 명령어로 여러 데이터를 동시 처리)는 기대만큼 효과가 크지 않음

  • 마이크로벤치마크에서는 최대 8.4배 향상되지만, 실제 TPC-H 쿼리에서는 조인 쿼리 기준 약 10% 향상에 그침
  • 이유: 대부분의 OLAP 쿼리는 계산이 아니라 메모리 접근(=데이터를 얼마나 빨리 가져오느냐)이 병목이라, 계산을 빠르게 하는 SIMD의 이점이 메모리 대기 시간에 묻혀버림

5. 멀티코어 병렬화: 둘 다 잘 확장되고, 격차가 오히려 줄어듦

  • “morsel-driven parallelism”(HyPer가 제안한 작업 분배 방식)을 두 엔진에 동일 적용 → 10코어에서 8~11배 정도의 준수한 스케일링
  • 흥미로운 점: 하이퍼스레딩을 켜면 두 모델 간 성능 격차가 줄어듭니다. 스레드가 늘수록 벡터화의 “명령어 수가 많다”는 단점이 하드웨어 차원에서 가려지기 때문

6. 하드웨어를 바꿔도 결론은 동일

Intel Skylake, AMD Threadripper, Intel Xeon Phi(Knights Landing) 세 플랫폼에서 실험했지만, 어느 하드웨어에서도 한쪽이 일방적으로 우세하지 않았습니다.


원시 성능 외의 실무적 차이 (8절)

저자들은 “성능 차이가 크지 않으니, 실제 선택은 다른 요인이 좌우한다”고 결론짓습니다.

 컴파일 (Typer 계열)벡터화 (Tectorwise 계열)
OLTP유리 (한 행짜리 쿼리를 저장 프로시저처럼 통째로 컴파일 가능)불리 (배치 처리 전제라 이점이 없음)
컴파일 시간불리 (쿼리마다 코드 생성/컴파일 필요)유리 (primitive가 이미 사전 컴파일됨)
프로파일링/디버깅어려움 (생성된 코드라 추적 힘듦)쉬움 (각 primitive 단위로 시간 측정 가능)
적응형 실행(런타임 최적화 변경)매우 어려움가능 (VectorWise의 micro-adaptive 최적화 사례)

결론

두 패러다임 사이에 절대적 승자는 없다. OLAP 워크로드에서는 성능이 비슷하고, 실질적 선택은 워크로드 성격(OLTP 지원 필요 여부), 프로파일링/디버깅 편의성, 컴파일 시간 리스크 같은 엔지니어링 트레이드오프에 달려있다는 것이 논문의 최종 메시지입니다. 실제로 최신 시스템들(HyPer + Data Blocks, Peloton 등)은 두 방식을 섞은 하이브리드로 수렴하는 추세라고 언급합니다.


DuckDB와의 직접적 연결

이번 논문은 지난번 Stonebraker 논문보다 DuckDB 엔진 내부와 훨씬 더 직접적으로 연결됩니다.

  • DuckDB는 이 논문이 다루는 “Tectorwise” 계열, 즉 벡터화 실행 엔진입니다. 실제로 DuckDB는 MonetDB/X100 혈통을 그대로 이어받았고(공동 창시자 Boncz가 X100/VectorWise의 원저자), 내부적으로 튜플을 ~2048개 단위 벡터로 처리합니다 — 이 논문 4.3절에서 실험한 “vector size” 튜닝이 실제로 DuckDB 소스코드에 반영돼 있는 값입니다.
  • 왜 DuckDB가 컴파일 방식(HyPer, Umbra류)이 아니라 벡터화를 택했는가에 대한 답이 이 논문에 있습니다: 벡터화는 (1) 임베디드 환경에서 컴파일 시간 오버헤드가 없고, (2) 디버깅·프로파일링이 쉬우며, (3) 구현 복잡도가 상대적으로 낮으면서도, (4) 대부분의 실제 워크로드가 이 논문이 보여준 대로 메모리 바운드라 컴파일 방식 대비 성능 손해가 크지 않기 때문입니다. 즉 “속도는 거의 동등한데 엔지니어링 비용이 훨씬 적은” 선택인 셈입니다.

앞서 배우신 “DuckDB는 컬럼 지향 + 벡터화 실행이라 빠르다”는 설명의 “벡터화”라는 단어가 정확히 이 논문에서 정의되고 실증된 개념입니다.







© 2026. by Lian Choi