템플릿
DuckDB 분석 운영에 바로 복사해 쓰는 세션 설정, S3, Parquet, profiling, OOM 대응 템플릿
핵심 요약
- 설명 대신 바로 복사해 path·region·memory·partition key만 바꿔 쓰는 DuckDB 운영 SQL 조각 모음입니다.
- 세션 기준선은 threads·memory_limit·temp_directory·max_temp_directory_size·preserve_insertion_order를 고정하고 duckdb_settings()로 검증합니다.
- 입력은 read_parquet 결과를 input_manifest 테이블로 고정해 재현성을 확보하고, scan·filter pushdown·join·집계는 EXPLAIN ANALYZE로 점검합니다.
- OOM 대응 템플릿은 threads/memory를 낮추고 spill용 temp_directory를 지정한 뒤 단계별 CREATE TABLE로 staging합니다.
- Publish는 staging prefix에 run_id 경로로 COPY한 뒤 별도 orchestration에서 검증 후 catalog pointer를 final로 전환합니다.
이 장은 설명보다 바로 복사해 쓰는 운영 조각에 집중합니다. 팀 표준에 맞춰 path, region, memory, partition key만 바꿔 쓰면 됩니다.
세션 기준선
SELECT version();
SET threads = 4;
SET memory_limit = '8GB';
SET temp_directory = '/mnt/fast-ssd/duckdb.tmp';
SET max_temp_directory_size = '200GB';
SET preserve_insertion_order = false;
SELECT name, value
FROM duckdb_settings()
WHERE name IN (
'threads',
'memory_limit',
'temp_directory',
'max_temp_directory_size',
'preserve_insertion_order'
)
ORDER BY name;S3 secret
INSTALL httpfs;
LOAD httpfs;
CREATE OR REPLACE SECRET lake_s3 (
TYPE s3,
PROVIDER credential_chain,
REGION 'ap-northeast-2',
SCOPE 's3://company-lake/'
);
SELECT *
FROM read_parquet('s3://company-lake/raw/events/dt=2026-05-14/*.parquet');Parquet metadata 점검
SELECT *
FROM parquet_schema('curated/orders.parquet')
ORDER BY name;
SELECT
file_name,
row_group_id,
row_group_num_rows,
total_compressed_size AS compressed_bytes,
compression
FROM parquet_metadata('curated/orders.parquet')
ORDER BY file_name, row_group_id;입력 manifest 고정
CREATE OR REPLACE TABLE input_manifest AS
SELECT DISTINCT filename
FROM read_parquet('s3://company-lake/raw/events/dt=2026-05-14/*.parquet');
COPY input_manifest
TO 's3://company-lake/manifests/events/dt=2026-05-14/files.csv'
(FORMAT csv, HEADER true);EXPLAIN ANALYZE 점검표
EXPLAIN ANALYZE
SELECT
customer_id,
date_trunc('month', order_date) AS month,
sum(amount) AS revenue
FROM read_parquet('s3://company-lake/curated/orders/**/*.parquet', hive_partitioning = true)
WHERE year = 2026
GROUP BY ALL
ORDER BY ALL;| 확인 | 질문 |
|---|---|
| scan | 필요한 파일만 읽는가 |
| filter | scan 단계로 pushdown되는가 |
| join | nested loop나 cardinality 폭발이 없는가 |
| aggregate | group key cardinality가 예상 범위인가 |
| sort/window | blocking operator가 전체 시간을 지배하지 않는가 |
OOM 대응 SQL
SET threads = 2;
SET memory_limit = '6GB';
SET preserve_insertion_order = false;
SET temp_directory = '/mnt/fast-ssd/duckdb-spill.tmp';
CREATE OR REPLACE TABLE stage_filtered AS
SELECT *
FROM read_parquet('s3://company-lake/raw/events/**/*.parquet')
WHERE event_date >= DATE '2026-05-01';
CREATE OR REPLACE TABLE stage_agg AS
SELECT user_id, event_name, count(*) AS events
FROM stage_filtered
GROUP BY ALL;Partition 설계표
| 후보 key | filter 빈도 | cardinality | partition당 예상 크기 | 채택 |
|---|---|---|---|---|
dt | 높음 | 일 단위 | 500MB | 예 |
tenant_id | 중간 | 수천 이상 | 불균등 | 아니오 |
region | 중간 | 5-20 | 충분 | 조건부 |
event_name | 낮음 | 수백 | 작음 | 아니오 |
Publish 패턴
COPY (
SELECT *
FROM mart_orders
) TO 's3://company-lake/staging/orders/run_id=20260514T090000Z'
(FORMAT parquet, PARTITION_BY (year, month), COMPRESSION zstd);
-- 이후 별도 orchestration 단계에서 row count, schema, partition size를 검증한 뒤
-- catalog pointer 또는 manifest를 final로 전환한다.