파티셔닝 쓰기
파티셔닝 쓰기 (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}');
덮어쓰기
기본적으로 파티셔닝 쓰기는 기존 디렉토리를 덮어쓰지 못해요. 로컬 파일 시스템에서는 OVERWRITE와 OVERWRITE_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을 사용해 처리해요.