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

시작과 기준선

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

파일·레이크 분석

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

분석 SQL·연동

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

성능·운영

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

부록

템플릿참고 자료검증 리포트업데이트 내역
핸드북›DuckDB 고급 활용›다중 파일·스키마 진화

다중 파일·스키마 진화

glob, filename virtual column, union_by_name, 스키마 drift 감지와 파일 manifest 운영 패턴을 다룹니다.

핵심 요약

  • glob과 read_parquet 배열로 다중 파일을 읽고, filename virtual column(DuckDB 1.3.0 이후 Parquet 기본)으로 파일 단위 품질 문제를 추적합니다.
  • 스키마가 다른 파일은 union_by_name=true로 없는 컬럼을 NULL로 채워 drift 조사에 쓰되, 운영 mart의 암묵적 표준으로 삼지 말고 컬럼 의도를 가려줄 registry를 둡니다.
  • expected schema 테이블과 parquet_schema()를 LEFT JOIN해 required 컬럼 누락·타입 불일치를 감지합니다.
  • glob은 재현성이 약하므로 중요한 batch는 glob 결과를 manifest table로 고정하고 재실행 시 같은 manifest를 사용합니다.
  • drift 대응은 nullable 추가는 registry 업데이트, required 누락은 batch fail, 타입 축소는 producer 수정 전까지 quarantine으로 나눕니다.

현실의 데이터 레이크는 깨끗한 파일 하나로 끝나지 않습니다. 날짜별, tenant별, job별 파일이 뒤섞이고, 과거 파일에는 새 컬럼이 빠져 있거나 타입이 다르기도 합니다. DuckDB의 multi-file read로 이 문제를 빠르게 들여다볼 수는 있지만, 운영 단계에서는 manifest와 schema contract가 따로 필요합니다.

다중 파일 읽기

SELECT *
FROM 'raw/events/**/*.parquet';

SELECT *
FROM read_parquet([
  'raw/events/2026-05-12/*.parquet',
  'raw/events/2026-05-13/*.parquet'
]);

파일 단위로 품질 문제를 추적할 때는 filename virtual column이 중요합니다. DuckDB 1.3.0 이후 Parquet read에서는 별도 설정 없이 바로 쓸 수 있습니다.

SELECT
  filename,
  count(*) AS rows,
  min(event_time) AS min_event_time,
  max(event_time) AS max_event_time
FROM read_parquet('raw/events/**/*.parquet')
GROUP BY filename
ORDER BY filename;

union_by_name

스키마가 다른 파일을 읽을 때는 union_by_name = true를 사용합니다. 없는 컬럼은 NULL로 채워집니다.

SELECT *
FROM read_parquet('raw/events/*.parquet', union_by_name = true);

drift를 조사할 때는 유용하지만, 이 옵션이 운영 mart의 암묵적 표준으로 굳어지면 곤란합니다. 새 컬럼이 의도된 것인지 provider 오류인지 가려줄 registry를 따로 둬야 합니다.

Schema contract 테이블

CREATE OR REPLACE TABLE expected_event_schema AS
SELECT *
FROM (VALUES
  ('event_id', 'VARCHAR', true),
  ('event_name', 'VARCHAR', true),
  ('event_time', 'TIMESTAMP', true),
  ('user_id', 'VARCHAR', false),
  ('properties', 'JSON', false)
) AS t(column_name, column_type, required);

WITH actual AS (
  SELECT name AS column_name, type AS column_type
  FROM parquet_schema('raw/events/2026-05-14/part-000.parquet')
)
SELECT e.*, a.column_type AS actual_type
FROM expected_event_schema e
LEFT JOIN actual a USING (column_name)
WHERE e.required AND a.column_name IS NULL
   OR a.column_type IS DISTINCT FROM e.column_type;

Manifest 운영

파일 glob은 편하지만 운영에서 같은 결과를 재현하기 어렵습니다. 중요한 batch라면 glob 결과를 manifest table로 고정해 둡니다.

CREATE OR REPLACE TABLE input_manifest AS
SELECT DISTINCT filename
FROM read_parquet('s3://lake/events/dt=2026-05-14/*.parquet');

COPY input_manifest
TO 'manifests/events_dt=2026-05-14.csv' (HEADER, DELIMITER ',');

재실행 시에는 같은 manifest를 사용합니다.

SELECT *
FROM read_parquet((SELECT list(filename) FROM input_manifest));

Drift 대응 기준

drift대응
nullable 컬럼 추가registry 업데이트 후 downstream 노출
required 컬럼 누락batch fail
타입 확대명시 cast와 회귀 테스트
타입 축소원본 producer 수정 전까지 quarantine
파일별 컬럼 순서 차이union_by_name 허용

참고 자료

  • Reading Multiple Files
  • Combining Schemas
  • Parquet Tips: union_by_name
  • Parquet Metadata

관련 문서

Parquet 레이크 모델링

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

Materialization·Index·통계

CTAS, persistent table, zonemap, ART index, ANALYZE를 DuckDB 성능 판단으로 연결합니다.

Ch4. 마이그레이션 전략

Prisma Production Guardrails · Expand/Contract 기반 무중단 마이그레이션과 위험 변경 분리 전략

Parquet 레이크 모델링

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

파티션 쓰기와 오브젝트 스토리지

Hive partitioning, S3 secrets, multipart write, small files 문제를 DuckDB 운영 기준으로 정리합니다.

On this page

다중 파일 읽기union_by_nameSchema contract 테이블Manifest 운영Drift 대응 기준참고 자료