성능 프로파일링
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를 함께 기록합니다.
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 operator | pre-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 version | optimizer/reader 변경 영향 |
| extension version | httpfs/lakehouse 동작 차이 |
| input files | glob 결과 변화 방지 |
| threads/memory/temp | 환경 차이 분리 |
| cold/warm cache | OS cache 영향 분리 |