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

시작과 기준선

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

파일·레이크 분석

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

분석 SQL·연동

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

성능·운영

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

부록

템플릿참고 자료검증 리포트업데이트 내역
핸드북›DuckDB 고급 활용›성능 프로파일링

성능 프로파일링

EXPLAIN, EXPLAIN ANALYZE, profiling output으로 DuckDB 쿼리 병목을 읽는 기준을 정리합니다.

핵심 요약

  • 성능 튜닝은 memory_limit부터 만지기 전에 plan을 읽는 일입니다. EXPLAIN(미실행 물리 계획), EXPLAIN ANALYZE(실행 operator runtime), profiling setting, duckdb_settings()를 씁니다.
  • EXPLAIN ANALYZE는 multi-thread에서 operator 시간 합이 전체 시간보다 클 수 있다는 점을 감안해 읽습니다.
  • scan 이후 filter는 pushdown 실패, nested loop join·cardinality 폭발은 join key/통계 문제, 과도한 file scan은 partition filter 부재 신호입니다.
  • 느린 쿼리는 EXPLAIN → EXPLAIN ANALYZE → 병목 구분(file layout / join·statistics / memory·blocking) → rewrite·materialize 루프로 다룹니다.
  • 벤치마크는 쿼리 시간만이 아니라 DuckDB·extension version, input files, threads/memory/temp, cold/warm cache를 함께 기록합니다.

2.0 성능·설정 변경

2.0의 asynchronous I/O는 원격 파일 읽기와 쿼리 처리의 병렬성을 분리합니다. 이전 버전의 threads 튜닝 결과를 그대로 적용하지 말고 같은 파일 manifest·필터·cold/warm 조건에서 다시 측정합니다. 특정 블로그의 속도 배수를 팀 SLA로 가져오지 않습니다.

custom_profiling_settings는 제거됐고 tracked_metrics로 옮깁니다. profiling_mode는 deprecated이며 값을 바꿔도 효과가 없습니다. HTTP 로그는 CALL enable_logging('HTTP'), CLI에서 조회 가능한 메모리 로그는 CALL enable_logging(storage = 'memory') 등 목적별로 설정합니다.

설정 변경 목록.

DuckDB 성능 튜닝은 추측 대신 plan을 읽는 일입니다. 파일 scan, filter pushdown, join order, blocking operator, thread 사용을 확인하지 않고 memory_limit만 바꾸면 문제를 뒤늦게 발견하게 됩니다.

기본 도구

도구실행 여부용도
EXPLAIN실행하지 않음물리 계획 확인
EXPLAIN ANALYZE실행함operator별 runtime 확인
profiling pragma/settings실행함JSON/파일 기반 profile 저장
duckdb_settings()실행함세션 설정 확인
EXPLAIN
SELECT customer_id, sum(amount) AS revenue
FROM read_parquet('curated/orders/*.parquet')
WHERE order_date >= DATE '2026-01-01'
GROUP BY customer_id;
EXPLAIN ANALYZE
SELECT customer_id, sum(amount) AS revenue
FROM read_parquet('curated/orders/*.parquet')
WHERE order_date >= DATE '2026-01-01'
GROUP BY customer_id;

EXPLAIN ANALYZE는 실제 실행하며 operator별 wall-clock time을 보여줍니다. multi-thread 실행에서는 operator 시간 합이 전체 시간보다 클 수 있습니다.

Plan에서 보는 것

신호해석대응
filter가 scan 이후에 적용pushdown 실패 가능expression 단순화, type cast 위치 조정
nested loop join작은 side가 맞는지 확인join condition, 통계, materialization 점검
cardinality 폭발join key 중복 또는 조건 누락key uniqueness 검사
file scan이 너무 많음partition filter 부재hive partition, manifest, path 제한
sort/window 시간이 큼blocking operatorpre-aggregate, partition 축소

Profile 루프

Benchmark 습관

SET threads = 4;
SET memory_limit = '8GB';
SET temp_directory = '/fast-temp/duckdb.tmp';

SELECT current_setting('threads'), current_setting('memory_limit');

쿼리 시간만 기록하지 말고 다음을 함께 기록합니다.

항목이유
DuckDB versionoptimizer/reader 변경 영향
extension versionhttpfs/lakehouse 동작 차이
input filesglob 결과 변화 방지
threads/memory/temp환경 차이 분리
cold/warm cacheOS cache 영향 분리

비동기 I/O의 적용 범위와 관측

2.0 비동기 읽기는 Parquet, 압축되지 않은 seekable UTF-8 CSV, native DuckDB 저장 포맷에 자동 적용됩니다. JSON 등은 동기 경로이므로 모든 파일이 같은 개선을 얻는다고 보지 않습니다.

SELECT name, value FROM duckdb_settings()
WHERE name IN ('threads', 'async_threads', 'read_ahead_depth', 'memory_limit')
ORDER BY name;

threads는 쿼리 처리, async_threads는 별도 I/O pool입니다. 여러 인스턴스를 함께 운영하면 두 pool을 합산해 자원 사용을 봅니다. read_ahead_depth=-1은 메모리 예산에 따라 제어하고, 양수는 앞서 읽는 job 수를 제한하지만 같은 메모리 예산 방식이 아닙니다. 0은 선행 읽기를 끕니다. 기본값부터 측정하고 CPU·네트워크·peak RSS·spill을 함께 비교합니다. I/O 문서.

2.0 EXPLAIN (SQL)

EXPLAIN (SQL) SELECT 1 + 2 AS answer;

최적화된 논리 계획을 실행 가능한 SQL로 확인합니다. 실제 쿼리를 실행하지 않으며, 출력의 별칭·문자열 포맷은 안정적인 API가 아닙니다. golden test에서 SQL 문자열 전체를 고정하기보다 결과 스키마와 의미를 검증합니다. ANALYZE·FORMAT과 함께 사용할 수 없습니다. Profiling Queries.

참고 자료

  • EXPLAIN: Inspect Query Plans
  • EXPLAIN ANALYZE
  • Profiling
  • Tuning Workloads
  • My Workload Is Slow

관련 문서

템플릿

DuckDB 분석 운영에 바로 복사해 쓰는 세션 설정, S3, Parquet, profiling, OOM 대응 템플릿

검증 리포트

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

On this page

2.0 성능·설정 변경기본 도구Plan에서 보는 것Profile 루프Benchmark 습관비동기 I/O의 적용 범위와 관측2.0 EXPLAIN (SQL)참고 자료