DuckDB — 파일 위에서 바로 분석하는 열 지향 엔진 · 파이프라인과 연동 · 이론
PostgreSQL 과 오가는 분석 파이프라인
한 줄 요약
DuckDB 는 PostgreSQL 을 대신하지 않고 옆에 선다. 운영 표를 그 자리에서 읽어 오고, 무거운 집계는 로컬 열 저장소에서 하고, 결과는 Parquet 나 PostgreSQL 표로 돌려보낸다. 파이프라인은 몇 번을 돌려도 같은 상태가 되어야 한다.
왜 이게 필요했나
운영 PostgreSQL 에 "국가별 월 매출" 을 물었다. 세 표를 조인하는 집계 하나가 몇 초를 먹고, 그동안 주문 API 의 응답이 흔들렸다. 운영 DB 는 한 행을 빠르게 찾는 데 맞춰져 있지, 300만 행을 훑는 데 맞춰져 있지 않다. 그렇다고 웨어하우스를 세우기엔 질문이 하루 몇 개다. 필요한 것은 운영 표를 한 번 읽어 와서 옆에서 집계할 곳이다.
어떻게 동작하나
DuckDB 의 postgres 확장이 그 다리다. 이미지에 미리 설치돼 있어서 LOAD postgres 만 하면 된다(인터넷이 없어 INSTALL 은 실패한다).
ATTACH 'dbname=labdb user=lab password=lab host=127.0.0.1' AS pg (TYPE postgres);select status, count(*) from pg.public.orders group by 1;pg.스키마.표 로 PostgreSQL 의 표가 DuckDB 안에서 보인다. 복사가 아니다 — 질의할 때마다 PostgreSQL 에서 읽어 온다. 필터는 그쪽으로 밀어 보내지만 조인과 집계는 DuckDB 가 하므로 표 전체가 매번 건너온다. 한 번 보고 말 질문이면 충분하고, 여러 번 물을 거면 create table orders as from pg.public.orders 로 복사한다. 이 순간부터 집계는 PostgreSQL 을 건드리지 않는다.
결과를 넘기는 형식은 Parquet 다. 스키마·형·압축이 파일 안에 있어서 받는 쪽이 아무 옵션도 필요 없다. CSV 로 넘기면 받는 쪽이 형을 다시 추론하고, 모듈 1에서 본 사고가 반복된다.
파이썬에서는 duckdb.connect('파일', read_only=True) 로 열고 con.sql(질의) 가 관계 객체를 돌려준다. .write_csv(), .df(), .fetchall() 이 거기 붙어 있다. read_only 는 보고서 스크립트가 실수로 표를 고치는 것을 막고, 다른 읽기 프로세스와 함께 열 수 있게 한다.
증분 적재가 파이프라인의 중심이다. 7월 파일이 두 번에 나눠 도착했고 전송 재시도 때문에 앞부분이 겹친다. 그냥 insert 하면 같은 판매가 두 번 들어간다.
create table sales (sale_id bigint primary key, ...);insert or ignore into sales select * from read_csv('incoming/2026-07-a.csv.gz');INSERT OR IGNORE 는 기본 키가 있어야 '이미 있는 행' 을 표가 스스로 알고 건너뛴다. 키 없이 하려면 where not exists (...) 안티 조인이지만 한 문장 안의 중복은 못 거른다. 어느 쪽이든 같은 파일을 두 번 읽어도 행이 늘지 않아야 한다.
되돌려 쓰기도 한 줄이다. create or replace table pg.public.duck_country_month as select * from country_month. 붙인 데이터베이스에 표를 만들면 PostgreSQL 쪽에 실제 표가 생긴다. OR REPLACE 가 중요하다 — 덧붙이는 대신 갈아 끼워야 두 번 돌려도 같은 표가 된다.
실무에서 진짜 중요한 것
첫째, 운영 DB 에는 읽으러만 간다. ATTACH 에 READ_ONLY 를 붙이면 실수로 쓰는 일이 원천적으로 막힌다. 되돌려 쓸 때만 따로 연다.
둘째, 멱등이 곧 파이프라인의 품질이다. 실패한 배치를 다시 돌릴 때 "어디까지 됐더라" 를 사람이 세어야 한다면 그 파이프라인은 사고를 기다리는 중이다. 기본 키·OR IGNORE·OR REPLACE 가 그 부담을 표에 넘긴다.
셋째, 두 번 돌려 본다. 다음 실습의 마지막 단계가 그것이다. 두 번째 실행 뒤 행 수가 그대로면 통과다.