본문으로 바로가기
리옵트 핸드북
리옵트 핸드북
DuckDB 고급 활용

시작과 기준선

포지셔닝과 적합한 워크로드버전·설치·런타임 기준연결·스토리지 모델실행 가능한 예제 번들

파일·레이크 분석

CSV·JSON 수집Parquet 레이크 모델링다중 파일·스키마 진화파티션 쓰기와 오브젝트 스토리지Lakehouse 포맷

분석 SQL·연동

Friendly SQL과 매크로시계열·분석 SQL중첩·반정형 데이터Python·Arrow·Polars·BIdbt·MotherDuck·Ibis 생태계Materialization·Index·통계

성능·운영

성능 프로파일링벤치마크·프로파일링 실습메모리·spill·실패 모드동시성·보안·운영보안 Hardening 체크리스트

부록

템플릿참고 자료검증 리포트업데이트 내역
핸드북›DuckDB 고급 활용›Parquet 레이크 모델링

Parquet 레이크 모델링

Parquet 직접 스캔, metadata 함수, row group, compression, materialization 기준을 정리합니다.

핵심 요약

  • DuckDB는 Parquet를 column projection·filter pushdown으로 직접 읽습니다. 다만 반복 쿼리나 join이 많을 때는 매번 decompression을 다시 하고 통계도 부족해서 DuckDB 테이블에 적재하는 편이 낫습니다.
  • 성능 문제는 SQL보다 파일 구조에서 비롯될 때가 많으니, parquet_schema·parquet_metadata로 파일 수, row group, compression, statistics를 먼저 봅니다.
  • 필터 후 읽을 파일 전체의 row group 수가 worker를 충분히 활용하는지 봅니다. 너무 작으면 metadata overhead가 커지고, 너무 크면 selective query와 병렬성이 약해집니다.
  • 자주 필터링하는 날짜·계정·tenant 컬럼으로 ORDER BY 정렬해 zonemap 효율을 높입니다.
  • compression은 snappy·zstd를 대표 입력으로 비교하고, gzip은 기존 소비자 호환 요구를 확인합니다. 같은 파일을 반복해서 직접 스캔한다면 무거운 compression이 오히려 불리합니다.

DuckDB와 Parquet는 함께 쓸 때 가치가 큽니다. DuckDB는 Parquet를 직접 읽으면서 column projection과 filter pushdown을 활용하고, metadata 함수로 파일 구조를 들여다봅니다. 하지만 모든 Parquet를 직접 스캔하는 것이 정답은 아닙니다.

직접 스캔과 적재의 기준

기준Parquet 직접 스캔DuckDB 테이블 적재
1회성 탐색적합과함
반복 쿼리가능하지만 매번 decompression유리
많은 join통계가 부족할 수 있음cardinality estimate가 유리
디스크 여유원본만 필요DB 파일만큼 추가 공간 필요
데이터 공유파일 lake와 잘 맞음단일 DB 파일 배포에 유리
-- 직접 스캔
SELECT region, sum(amount) AS revenue
FROM 's3://lake/orders/year=2026/month=*/part-*.parquet'
WHERE order_date >= DATE '2026-01-01'
GROUP BY ALL;

-- 반복 분석용 적재
CREATE OR REPLACE TABLE orders AS
SELECT *
FROM read_parquet('s3://lake/orders/**/*.parquet', hive_partitioning = true);

Metadata를 먼저 본다

SELECT *
FROM parquet_schema('curated/orders.parquet');

SELECT
  file_name,
  row_group_id,
  row_group_num_rows,
  compression
FROM parquet_metadata('curated/orders.parquet');

Parquet 성능 문제는 SQL보다 파일 구조에서 비롯될 때가 많습니다. 파일 수, row group 수, compression, column type, min/max statistics가 필터 pushdown과 병렬성을 좌우합니다.

Row group 설계

DuckDB 문서는 Parquet row group size 기본값과 병렬성의 관계를 설명합니다. 단일 파일이면 여러 row group이 필요하고, 다중 파일이면 읽을 파일 전체의 row group 수를 함께 봅니다. row group이 너무 작으면 metadata overhead가 커지고, 너무 크면 selective query와 병렬성이 약해집니다.

COPY (
  SELECT *
  FROM orders
  ORDER BY order_date, customer_id
) TO 'curated/orders.parquet'
  (FORMAT parquet, COMPRESSION zstd, ROW_GROUP_SIZE 100000);

정렬은 zonemap 효율을 높입니다. 날짜, 계정, tenant처럼 자주 필터링하는 컬럼이 있다면 output을 만들 때 정렬 순서를 의도적으로 잡아 둡니다.

Compression 선택

방식특징권장
snappy빠른 압축/해제, 넓은 호환성기본 운영
zstd압축률과 속도의 균형저장 비용이 중요할 때
gzip해제 비용이 큼기존 파일 호환 외에는 피함

DuckDB performance guide는 무거운 compression이 반복 직접 스캔에서 불리할 수 있다고 설명합니다. 같은 파일을 거듭 분석한다면 DuckDB 테이블로 적재하거나 가벼운 compression으로 다시 씁니다.

2.0 포맷 경계

비동기 I/O는 전송 대기를 줄이지만 row group 크기·필터 선택도·압축 해제 비용을 없애지는 않습니다. tiny file을 많이 만들기 전에 I/O 관측으로 네트워크와 CPU 병목을 분리합니다.

VARIANT를 Parquet에 저장한다면 다른 reader가 그 표현을 지원하는지 읽기 회귀를 추가합니다. 범용 BI용 파일에는 typed projection을 제공할 수 있습니다. native .duckdb의 storage version 69와 Parquet 파일 포맷은 서로 다른 호환성 계약입니다.

2.0 reader 옵션을 선택하는 기준

옵션점검할 계약
file_row_group_number파일 내 0부터 시작하는 row group 추적; filename과 함께 식별
int96_aslegacy INT96 timestamp의 정밀도와 표현 범위
utf8_validation기본 strict 오류와 replace/ignore에 따른 데이터 변형을 구분
prefetch_strategy기본 auto와 whole_group의 원격 읽기량·메모리 비교

오염된 UTF-8을 무조건 제거하거나 timestamp 정밀도를 조용히 낮추면 원본 손상을 숨길 수 있습니다. 품질 검사와 reader 옵션 변경을 한 검토 단위로 다룹니다. Parquet 2.0.

참고 자료

  • Reading and Writing Parquet Files
  • Parquet Tips
  • Performance Guide: File Formats
  • Indexing and Zonemaps

관련 문서

벤치마크·프로파일링 실습

같은 DuckDB 쿼리를 파일 레이아웃과 세션 설정별로 비교하는 재현 가능한 실습 절차입니다.

실행 가능한 예제 번들

작은 CSV·JSON 샘플과 DuckDB SQL 스크립트로 수집, Parquet 변환, profiling을 직접 실행합니다.

On this page

직접 스캔과 적재의 기준Metadata를 먼저 본다Row group 설계Compression 선택2.0 포맷 경계2.0 reader 옵션을 선택하는 기준참고 자료