벤치마크·프로파일링 실습
DuckDB 쿼리를 파일 레이아웃과 세션 설정별로 비교하고 재현 가능한 벤치마크·프로파일링 절차를 만드는 실습 가이드입니다.
핵심 요약
- DuckDB version과 input manifest를 고정한 뒤 cold/warm cache를 나눠 측정하고,
EXPLAIN ANALYZE로 scan·filter·aggregate·sort 시간 분포를 봅니다. - 한 번에 하나의 변수만 바꿉니다. 파일 레이아웃을 바꾸면 쿼리·세션 설정을 그대로 두고, 세션 설정을 바꾸면 입력 파일을 그대로 둡니다.
- 비교 축은 CSV vs Parquet, 정렬 전/후 Parquet(zonemap), row group size,
threads,memory_limit입니다. - 숫자 하나만 보지 말고 plan shape이 바뀌었는지 확인하고, version·client·settings·cold/warm runtime·결론을 기록 양식에 남깁니다.
- thread를 늘려도 안 빨라지면 single file/row group이나 I/O bottleneck을, warm cache만 빠르면 storage latency가 지배한다고 해석합니다.
성능 튜닝 문서는 숫자보다 절차가 중요합니다. 노트북에서 한 번 빠르게 나온 결과는 OS cache, thread 수, 파일 layout, object storage latency에 쉽게 흔들립니다. 이 장에서 "우리 환경에서 같은 쿼리를 어떻게 비교할지"를 표준 절차로 정리합니다.
실습 목표
| 비교 | 질문 |
|---|---|
| CSV vs Parquet | 반복 분석 전에 columnar 변환이 필요한가 |
| 정렬 전/후 Parquet | zonemap 효과가 있는가 |
| row group size | 병렬성과 metadata overhead 균형이 맞는가 |
async_threads / read_ahead_depth | 원격 I/O와 선행 읽기 변화가 RSS·runtime에 주는 영향 |
threads | CPU thread 증가가 실제 runtime을 줄이는가 |
memory_limit | spill 없이 안정적으로 실행되는 하한은 어디인가 |
절차
기준 SQL
SET threads = 4;
SET memory_limit = '8GB';
SET preserve_insertion_order = false;
EXPLAIN ANALYZE
SELECT
region,
plan,
sum(amount) AS revenue,
count(*) AS orders
FROM read_parquet('/tmp/duckdb-advanced-orders.parquet')
WHERE ordered_at >= TIMESTAMP '2026-05-01 00:00:00'
GROUP BY ALL
ORDER BY ALL;EXPLAIN ANALYZE 결과에서 scan, filter, aggregate, sort의 시간이 어디에 몰리는지 먼저 봅니다. 숫자 하나만 보지 말고 plan shape이 바뀌었는지 확인합니다.
한 번에 하나만 바꾼다
SET threads = 1;
-- same query
SET threads = 4;
-- same queryCOPY (
SELECT *
FROM orders
ORDER BY ordered_at, customer_id
) TO '/tmp/duckdb-advanced-orders-rg.parquet'
(FORMAT parquet, COMPRESSION zstd, ROW_GROUP_SIZE 100000);파일 레이아웃을 바꿨다면 쿼리와 세션 설정을 그대로 둡니다. 세션 설정을 바꿨다면 입력 파일을 그대로 둡니다.
기록 양식
| 항목 | 값 |
|---|---|
| DuckDB version | SELECT version() |
| client | CLI / Python / dbt-duckdb / Ibis |
| input manifest | 파일 수, 전체 크기, row group 수 |
| settings | threads, async_threads, read_ahead_depth, memory_limit, temp_directory |
| cold run | runtime, 주요 병목 |
| warm run | runtime, 주요 병목 |
| 결론 | 채택할 파일 layout 또는 세션 설정 |
해석 기준
| 관찰 | 해석 |
|---|---|
| thread를 늘려도 빨라지지 않음 | single file/row group, I/O bottleneck, blocking operator 가능 |
| 정렬 후 selective filter가 빨라짐 | zonemap 효과 가능 |
| Parquet가 CSV보다 훨씬 빠름 | 반복 분석 전 변환 가치 있음 |
| memory를 늘려도 변화 없음 | CPU/I/O 또는 file layout 병목 |
| warm cache만 빠름 | storage latency가 지배적일 수 있음 |
2.0 전환 비교표
같은 manifest와 쿼리로 1.5와 2.0을 비교하되 먼저 결과 행·타입·NULL·합계가 같은지 검증합니다. 파일 생성 엔진과 저장 포맷도 기록합니다. 새 2.0 DB 파일을 1.5 비교군의 입력으로 넘기지 않습니다.
작은 예제 번들은 실행 흐름 검증용이며 S3 속도 개선이나 row group 병렬성을 증명하지 못합니다. 실측에는 여러 row group이 있는 대표 입력을 사용하고, 최초 실행이 실제 cold cache인지 확인합니다. 프로세스 재시작만으로 OS·원격 캐시가 비워지지는 않습니다. 2.0 I/O.