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

시작과 기준선

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

파일·레이크 분석

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

분석 SQL·연동

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

성능·운영

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

부록

템플릿참고 자료검증 리포트업데이트 내역
핸드북›DuckDB 고급 활용›Materialization·Index·통계

Materialization·Index·통계

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

핵심 요약

  • materialization은 속도용 복사가 아니라 통계와 반복 실행을 위해 상태를 남길지 정하는 일이며, 같은 파일을 반복해서 읽거나 join 계획이 불안정하거나 CSV/JSON을 반복 읽거나 결과가 downstream 계약이면 적재 신호입니다.
  • zonemap은 일반 type 컬럼에 자동 생성되어 min/max로 row group을 건너뛰므로, 자주 필터링하는 날짜·tenant·region 기준으로 ORDER BY 정렬해두면 이득이 큽니다.
  • ART index는 선택도가 높은 단일 컬럼 equality·IN과 constraint check에 유리합니다. join·집계·정렬용 만능 인덱스가 아니며, scan 단계의 동적 필터 활용은 실행 계획으로 판단합니다.
  • VIEW는 항상 다시 계산되므로 반복 비용이 크거나 특정 시점 snapshot이 필요하면 CTAS로 table에 materialize합니다.

DuckDB에서 materialization은 "속도를 위해 복사할지"가 아니라 "통계와 반복 실행을 위해 상태를 남길지"를 정하는 일입니다. 파일을 바로 읽는 쪽이 단순하지만, 반복 join이나 복잡한 view가 많고 decompression 비용이 높거나 join order가 어긋나면 적재가 낫습니다.

Materialization 기준

신호판단
같은 Parquet를 여러 번 읽는다DuckDB table 또는 중간 Parquet 생성
join이 많고 계획이 흔들린다DuckDB table로 적재 후 통계 활용
CSV/JSON을 반복 읽는다Parquet 또는 DuckDB table로 변환
결과가 downstream 계약이다curated Parquet로 publish
탐색성 ad hoc 쿼리다직접 scan 유지
CREATE OR REPLACE TABLE orders AS
SELECT *
FROM read_parquet('raw/orders/**/*.parquet', hive_partitioning = true);

ANALYZE orders;

Zonemap

DuckDB는 일반-purpose type 컬럼에 zonemap을 자동 생성합니다. min/max 범위로 row group을 건너뛰므로, 자주 필터링하는 컬럼 기준으로 데이터가 어느 정도 정렬돼 있으면 이득이 큽니다.

CREATE OR REPLACE TABLE events_ordered AS
SELECT *
FROM events
ORDER BY event_date, tenant_id;

날짜, 증가 integer, tenant, region처럼 selective filter가 반복되는 컬럼은 정렬 후보입니다.

ART index

ART index는 primary key나 unique constraint에서 암묵적으로 생기거나 CREATE INDEX로 직접 만듭니다. 다만 모든 분석 쿼리를 빠르게 해주는 만능 도구는 아닙니다.

ART index가 유리한 경우피해야 할 경우
단일 컬럼 equality lookup대규모 scan, aggregate
IN (...) 조건join/aggregation/sort 가속 기대
constraint check가 필요write-heavy table

ART를 join·aggregation·sort 자체를 가속하는 인덱스로 보지 않습니다. 다만 hash join에서 내려온 dynamic filter가 scan의 ART 탐색을 유도할 수 있습니다. 단일 컬럼·비표현식 인덱스인지, 실제 계획에서 index scan이 선택됐는지 확인합니다. ART index scans.

CREATE INDEX idx_customers_id ON customers(customer_id);

View와 table

CREATE OR REPLACE VIEW active_customers AS
SELECT *
FROM customers
WHERE status = 'active';

CREATE OR REPLACE TABLE active_customers_snapshot AS
SELECT *
FROM active_customers;

view는 호출할 때마다 다시 계산됩니다. 반복 비용이 크거나 특정 시점 snapshot이 필요하면 table로 materialize합니다.

2.0 트리거: 변경 내역과 증분 유지

CREATE TRIGGER로 테이블 변경에 반응하는 SQL을 등록합니다. 배치 처리에는 statement 단위와 transition table이 유용합니다. 다음 예제는 변경 전후 값을 남기며, 조인 키 id가 바뀌지 않는다는 전제를 둡니다.

CREATE TABLE accounts (id INTEGER PRIMARY KEY, balance INTEGER);
CREATE TABLE balance_audit (id INTEGER, before_balance INTEGER, after_balance INTEGER);
CREATE TRIGGER audit_balance
  AFTER UPDATE ON accounts
  REFERENCING OLD TABLE AS before_rows NEW TABLE AS after_rows
  FOR EACH STATEMENT
  INSERT INTO balance_audit
  SELECT a.id, b.balance, a.balance
  FROM before_rows b JOIN after_rows a USING (id);
INSERT INTO accounts VALUES (1, 100), (2, 200);
UPDATE accounts SET balance = balance + 10;
SELECT * FROM balance_audit ORDER BY id; -- (1,100,110), (2,200,210)

트리거로 집계 테이블을 유지할 수 있지만 자동 materialized view 관리와는 다릅니다. 초기 적재, UPDATE/DELETE 보정, 재처리 중복, 전체 재계산과의 일치를 직접 설계합니다.

2.0에서는 BEFORE ... FOR EACH ROW, row 단위 UPDATE, view의 트리거, 임시 트리거를 지원하지 않습니다. 트리거가 있는 테이블의 MERGE INTO와 row 트리거의 RETURNING에도 제한이 있습니다. ON CONFLICT 계열 적재와 함께 쓰기 전에 지원 조합을 확인합니다. CREATE TRIGGER와 제한.

참고 자료

  • CREATE TABLE
  • ANALYZE
  • Indexing Performance Guide
  • CREATE INDEX
  • Performance Guide: File Formats

관련 문서

Parquet 레이크 모델링

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

검증 리포트

DuckDB 고급 활용 핸드북의 구조·링크·공식 근거·버전 기준 검증 결과

On this page

Materialization 기준ZonemapART indexView와 table2.0 트리거: 변경 내역과 증분 유지참고 자료