메모리·spill·실패 모드
larger-than-memory, temp directory, OOM, blocking operator, thread 제한을 운영 runbook으로 정리합니다.
핵심 요약
- DuckDB는 disk spill로 larger-than-memory를 지원하지만 모든 연산이 spill되지는 않습니다. OOM killer나 temp directory 부족으로 프로세스가 죽을 수 있으니 실패 모드별로 대응을 준비해 둡니다.
- memory_limit 기본은 RAM 80%이고 buffer manager에만 적용됩니다. buffer manager 밖 메모리를 쓰는 연산이 있어 운영에서는 전체 RAM의 50-60%로 낮추는 편이 안정적입니다.
- grouping·joining·sorting·windowing은 blocking operator로 입력 전체/큰 중간 상태가 필요하므로 사전 필터, key 축소, partition별 처리로 다룹니다.
- OOM 대응은 EXPLAIN ANALYZE로 operator 확인 → threads 감소 → preserve_insertion_order=false → temp_directory 이동 → memory_limit 하향 → stage table 분해 순서입니다.
- OutOfMemoryException은 내부 한도, process Killed는 OS OOM killer, temp full은 spill 공간 부족으로 구분해 조치를 매핑합니다.
DuckDB는 larger-than-memory workload를 지원하고 disk spill을 씁니다. 하지만 모든 연산이 항상 spill되지는 않고, Linux OOM killer나 temp directory 부족으로 프로세스가 죽기도 합니다. DBA가 준비할 것은 "메모리 한도 설정"이 아니라 "실패 모드별 대응"입니다.
기본 설정
SET memory_limit = '8GB';
SET threads = 4;
SET temp_directory = '/mnt/fast-ssd/duckdb.tmp';
SET max_temp_directory_size = '200GB';
SET preserve_insertion_order = false;memory_limit 기본값은 RAM의 80%이고, 이 한도는 buffer manager에만 적용됩니다. 일부 연산은 buffer manager 밖 메모리를 쓰기 때문에, 운영에서는 전체 RAM의 50-60% 수준으로 낮추는 편이 오히려 안정적입니다.
Blocking operator
DuckDB 문서는 grouping, joining, sorting, windowing을 대표적인 blocking operator로 설명합니다. 이런 연산은 입력 전체나 큰 중간 상태가 있어야 돌아갑니다.
| 연산 | 위험 | 대응 |
|---|---|---|
GROUP BY | high cardinality state | 사전 필터, key 축소 |
JOIN | cardinality explosion | key uniqueness, join order 점검 |
ORDER BY | 전체 정렬 buffer | limit pushdown, partition별 처리 |
| window | partition별 state | partition key와 frame 제한 |
PIVOT | 내부 list 사용 | pivot value 제한 |
OOM 대응 순서
EXPLAIN ANALYZE로 어느 operator에서 커지는지 확인합니다.threads를 줄입니다.preserve_insertion_order = false를 검토합니다.temp_directory를 빠르고 여유 있는 디스크로 옮깁니다.memory_limit을 전체 RAM보다 낮게 잡아 OS OOM killer를 피합니다.- query를 stage table로 나눠 중간 폭발 지점을 분리합니다.
CREATE OR REPLACE TABLE stage_filtered AS
SELECT *
FROM read_parquet('s3://lake/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;temp directory 운영
| 기준 | 권장 |
|---|---|
| 위치 | OS root가 아닌 빠른 SSD mount |
| 용량 | 예상 spill보다 충분히 크게 |
| 격리 | job/run별 temp path |
| 정리 | 실패 후 temp directory cleanup |
| 모니터링 | disk free, inode, write throughput |
실패 모드 매핑
| 메시지/증상 | 가능한 원인 | 조치 |
|---|---|---|
OutOfMemoryException | DuckDB 내부 한도 도달 | threads 감소, query 분해 |
process Killed | OS OOM killer | memory_limit 낮춤, dmesg 확인 |
| temp directory full | spill 공간 부족 | max_temp_directory_size, mount 용량 확인 |
| long checkpoint | 큰 DB 파일과 변경 | batch window 조정 |
| crash 후 fatal mode | internal error 후 invalidated | process 재시작, 최소 재현 제출 |