파티셔닝 쓰기

파티셔닝 쓰기 (Partitioned Writes)

DuckDB의 COPY 문에 PARTITION_BY 절을 쓰면 테이블을 Hive 파티셔닝 구조의 디렉토리로 나눠 쓸 수 있어요. 대용량 데이터를 나중에 파티션 단위로 조회·관리하고 싶을 때 유용하죠.

출처: 공식문서

예시

Parquet 파일로 된 Hive 파티션 데이터셋에 테이블 쓰기:

COPY orders TO 'orders'
(FORMAT parquet, PARTITION_BY (year, month));

CSV 파일로 쓰되 덮어쓰기를 허용하려면:

COPY orders TO 'orders'
(FORMAT csv, PARTITION_BY (year, month), OVERWRITE_OR_IGNORE);

데이터 파일 확장자를 명시하면서 GZIP 압축된 CSV로 쓰기:

COPY orders TO 'orders'
(FORMAT csv, PARTITION_BY (year, month), COMPRESSION gzip, FILE_EXTENSION 'csv.gz');

파티셔닝 쓰기 방식

COPY 문PARTITION_BY 절을 지정하면 파일이 Hive 파티셔닝 폴더 계층으로 쓰여져요. 이때 대상(orders)은 최상위 루트 디렉토리 이름이 되고, 파일은 파일 계층 안에서 순서대로 쓰여요. 현재는 스레드별로 각 디렉토리에 파일을 하나씩 만들어요.

orders
├── year=2021
│    ├── month=1
│    │   ├── data_1.parquet
│    │   └── data_2.parquet
│    └── month=2
│        └── data_1.parquet
└── year=2022
     ├── month=11
     │   ├── data_1.parquet
     │   └── data_2.parquet
     └── month=12
         └── data_1.parquet

파티션 값은 데이터에서 자동으로 추출돼요. 여기서 한 가지 짚고 갈게요 — 파티션 수가 많아지면 파일도 그만큼 많이 생겨서 쓰기 비용이 커질 수 있어요. 이상적인 파티션 개수는 데이터셋 크기에 따라 달라져요.

PARTITION_BY로 쓸 때 시스템이 디스크에 flush하기 전까지 열어둘 수 있는 최대 파일 수를 제한하려면 partitioned_write_max_open_files 설정 옵션을 쓰세요. 기본값은 100이에요.

SET partitioned_write_max_open_files = 10;

권장 사항 — 너무 많은 작은 파티션으로 데이터를 쓰는 건 비용이 커요. 파티션당 데이터가 최소한 100 MB는 되도록 잡는 게 일반적인 가이드라인이에요.

파일 이름 패턴

기본적으로 파일은 data_0.parquet 또는 data_0.csv처럼 이름이 지어져요. FILENAME_PATTERN 플래그로 {i}{uuid} 패턴을 지정하면 원하는 파일 이름을 만들 수 있어요.

  • {i}는 인덱스로 치환돼요.
  • {uuid}는 128비트 길이의 UUID로 치환돼요.

파일 이름에 인덱스를 넣어 Parquet Hive 파티션 데이터셋에 쓰기:

COPY orders TO 'orders'
(FORMAT parquet, PARTITION_BY (year, month), OVERWRITE_OR_IGNORE, FILENAME_PATTERN 'orders_{i}');

파일마다 고유한 이름을 만들려면:

COPY orders TO 'orders'
(FORMAT parquet, PARTITION_BY (year, month), OVERWRITE_OR_IGNORE, FILENAME_PATTERN 'file_{uuid}');

덮어쓰기

기본적으로 파티셔닝 쓰기는 기존 디렉토리를 덮어쓰지 못해요. 로컬 파일 시스템에서는 OVERWRITEOVERWRITE_OR_IGNORE 옵션이 기존 디렉토리를 제거해요. 원격 파일 시스템에서는 덮어쓰기를 지원하지 않아요.

추가 쓰기

기존 Hive 파티션 디렉토리 구조에 데이터를 추가하려면 APPEND 옵션을 쓰세요.

COPY orders TO 'orders'
(FORMAT parquet, PARTITION_BY (year, month), APPEND);

APPEND 옵션은 OVERWRITE_OR_IGNORE, FILENAME_PATTERN '{uuid}'와 비슷하게 동작하지만, 한 가지가 달라요. DuckDB가 파일이 이미 있는지 한 번 더 확인한 뒤, 드물게 이미 존재하면 충돌을 피하기 위해 UUID를 다시 만들어요.

컬럼 안의 슬래시 처리

컬럼 이름에 슬래시가 들어 있으면 url_encode 함수가 구현하는 Percent-Encoding을 사용해 처리해요.

더 알아보기 (Learn more)