Parquet
Parquet
Parquet는 읽고 처리하기에 효율적인 컬럼형(columnar) 압축 파일이에요. DuckDB는 Parquet 파일을 효율적으로 읽고 쓰는 것은 물론, 필터(filter)와 프로젝션(projection)을 Parquet 파일 스캔에 밀어 넣는 작업(pushdown)까지 지원합니다.
참고
Parquet 데이터셋은 파일 개수, 개별 파일의 크기, 사용하는 압축 알고리즘, row group 크기 등에 따라 차이가 있어요. 이런 요소들이 성능에 큰 영향을 주므로, 자세한 내용은 성능 가이드를 참고하세요.
예시
단일 Parquet 파일 읽기:
SELECT * FROM 'test.parquet';
Parquet 파일에 어떤 컬럼·타입이 들어 있는지 확인할 때:
DESCRIBE SELECT * FROM 'test.parquet';
Parquet 파일로부터 테이블 생성:
CREATE TABLE test AS
SELECT * FROM 'test.parquet';
파일 확장자가 .parquet로 끝나지 않는다면 read_parquet 함수를 써요:
SELECT *
FROM read_parquet('test.parq');
리스트 파라미터를 써서 세 개의 Parquet 파일을 하나의 테이블처럼 읽을 때:
SELECT *
FROM read_parquet(['file1.parquet', 'file2.parquet', 'file3.parquet']);
glob 패턴에 맞는 모든 파일 읽기:
SELECT *
FROM 'test/*.parquet';
glob 패턴에 맞는 모든 파일을 읽고, 각 행이 어느 파일에서 왔는지 알려주는 filename 가상 컬럼까지 포함하려면 (이 컬럼은 DuckDB v1.3.0부터 별도 설정 없이 기본으로 사용할 수 있어요):
SELECT *, filename
FROM read_parquet('test/*.parquet');
두 개의 특정 폴더에 있는 모든 Parquet 파일을 glob 리스트로 읽을 때:
SELECT *
FROM read_parquet(['folder1/*.parquet', 'folder2/*.parquet']);
HTTPS로 읽기:
SELECT *
FROM read_parquet('https://some.url/some_file.parquet');
Parquet 파일의 메타데이터 조회:
SELECT *
FROM parquet_metadata('test.parquet');
Parquet 파일의 파일 메타데이터 조회:
SELECT *
FROM parquet_file_metadata('test.parquet');
Parquet 파일의 key-value 메타데이터 조회:
SELECT *
FROM parquet_kv_metadata('test.parquet');
Parquet 파일의 스키마 조회:
SELECT *
FROM parquet_schema('test.parquet');
쿼리 결과를 기본 압축(Snappy)으로 Parquet 파일에 쓰기:
COPY
(SELECT * FROM tbl)
TO 'result-snappy.parquet'
(FORMAT parquet);
쿼리 결과를 특정 압축과 row group 크기로 Parquet 파일에 쓰기:
COPY
(FROM generate_series(100_000))
TO 'test.parquet'
(FORMAT parquet, COMPRESSION zstd, ROW_GROUP_SIZE 100_000);
데이터베이스 전체의 테이블 내용을 parquet로 내보내기:
EXPORT DATABASE 'target_directory' (FORMAT parquet);
Parquet 파일
Parquet 파일은 읽고 처리하기에 효율적인 압축된 컬럼형 파일이에요. DuckDB는 Parquet 파일을 효율적으로 읽고 쓰는 것은 물론, 필터와 프로젝션을 Parquet 파일 스캔에 밀어 넣는 작업까지 지원합니다.
read_parquet 함수
| 함수 | 설명 | 예시 |
|---|---|---|
read_parquet(path_or_list_of_paths) |
Parquet 파일 읽기 | SELECT * FROM read_parquet('test.parquet'); |
parquet_scan(path_or_list_of_paths) |
read_parquet의 별칭 |
SELECT * FROM parquet_scan('test.parquet'); |
파일 확장자가 .parquet로 끝나면 함수 문법은 선택사항이에요. 시스템이 Parquet 파일을 읽고 있다고 자동으로 추론합니다:
SELECT * FROM 'test.parquet';
여러 파일은 glob이나 파일 리스트를 제공해 한 번에 읽을 수 있어요. 자세한 내용은 여러 파일 섹션을 참고하세요.
파라미터
read_parquet 함수나 COPY 문에 넘길 수 있는 옵션이 몇 가지 있어요.
| 이름 | 설명 | 타입 | 기본값 |
|---|---|---|---|
binary_as_string |
레거시 작성기(writer)가 만든 Parquet 파일은 문자열의 UTF8 플래그를 올바르게 설정하지 못해 문자열 컬럼이 BLOB으로 로드되기도 해요. 이 값을 true로 설정하면 바이너리 컬럼을 문자열로 로드합니다. |
BOOL |
false |
can_have_nan |
FLOAT·DOUBLE 컬럼에 NaN 값이 있을 수 있는지 여부. true로 설정하면 reader가 컬럼의 min/max 통계를 사용한 필터 pushdown에서 NaN을 고려해요. NaN은 순서 비교가 되지 않기 때문이죠. |
BOOL |
false |
encryption_config |
Parquet 암호화 설정. | STRUCT |
- |
filename |
결과에 추가 filename 컬럼을 포함할지 여부. DuckDB v1.3.0부터 filename 컬럼은 자동으로 가상 컬럼으로 추가되어 이 옵션은 호환성 목적으로만 유지됩니다. |
BOOL |
false |
file_row_number |
file_row_number 컬럼을 포함할지 여부. |
BOOL |
false |
hive_partitioning |
경로를 Hive 파티셔닝 경로로 해석할지 여부. | BOOL |
(자동 감지) |
union_by_name |
여러 스키마의 컬럼을 위치 기준이 아니라 이름 기준으로 통합할지 여부. | BOOL |
false |
schema |
Parquet 파일을 지정한 스키마를 가진 것처럼 읽을 수 있게 해줘요. 필드 ID가 필요합니다. | MAP |
NULL |
schema 파라미터 사용하기
schema 파라미터를 쓰면 Parquet 파일을 특정 스키마로 읽을 수 있어요. Parquet 파일을 읽을 때 컬럼 이름 바꾸기, 추가, 삭제, 재정렬, 캐스팅(casting)에 유용합니다.
schema 파라미터를 쓰려면 필드 ID가 필요해요. DuckDB로 Parquet을 만들 때 필드 ID를 사용할 수 있게 하려면:
COPY (SELECT 42::INTEGER AS i) TO 'integers.parquet' (FIELD_IDS {i: 0});
Parquet 파일 읽기:
SELECT *
FROM read_parquet('integers.parquet', schema = MAP {
0: {name: 'renamed_i', type: 'BIGINT', default_value: NULL},
1: {name: 'new_column', type: 'UTINYINT', default_value: 43}
});
┌───────────┬────────────┐
│ renamed_i │ new_column │
│ int64 │ uint8 │
├───────────┼────────────┤
│ 42 │ 43 │
└───────────┴────────────┘
참고
schema파라미터는union_by_name = true와 함께 쓸 수 없어요.
부분 읽기 (Partial Reading)
DuckDB는 Parquet 파일 자체에 프로젝션 pushdown을 지원해요. 즉 Parquet 파일을 조회할 때 쿼리에 필요한 컬럼만 읽는다는 뜻입니다. 관심 있는 Parquet 파일의 일부만 읽을 수 있도록 해주고, 이 작업은 DuckDB가 자동으로 처리합니다.
DuckDB는 Parquet reader에 필터 pushdown도 지원해요. Parquet 파일에서 스캔되는 컬럼에 필터를 적용하면 그 필터가 스캔 안으로 밀려 들어가고, 내장된 zonemap을 이용해 파일의 일부를 건너뛰는 데도 쓸 수 있죠. 다만 이것은 Parquet 파일에 zonemap이 있는지에 따라 달라져요.
필터·프로젝션 pushdown은 상당한 성능 이점을 줍니다. 자세한 내용은 블로그 포스트 "Querying Parquet with Precision Using DuckDB"를 참고하세요.
Insert와 View
Parquet 파일의 데이터를 테이블에 직접 넣거나, Parquet 파일로부터 곧바로 테이블을 만들 수도 있어요. 이렇게 하면 Parquet 파일에서 데이터를 로드해 데이터베이스에 넣게 됩니다.
Parquet 파일의 데이터를 테이블에 넣기:
INSERT INTO people
SELECT * FROM read_parquet('test.parquet');
Parquet 파일로부터 직접 테이블 생성:
CREATE TABLE people AS
SELECT * FROM read_parquet('test.parquet');
데이터를 Parquet 파일 안에 그대로 두고 싶지만 Parquet 파일을 직접 조회하고 싶다면, read_parquet 함수 위에 view를 만들면 돼요. 그러면 Parquet 파일을 마치 내장 테이블처럼 조회할 수 있습니다.
Parquet 파일 위에 view 생성:
CREATE VIEW people AS
SELECT * FROM read_parquet('test.parquet');
Parquet 파일 조회:
SELECT * FROM people;
Parquet 파일에 쓰기
DuckDB는 COPY 문 문법으로 Parquet 파일에 쓰는 것도 지원해요. COPY 문의 가능한 모든 파라미터를 포함한 자세한 내용은 COPY 문 페이지를 참고하세요.
쿼리를 Snappy 압축 Parquet 파일로 쓰기:
COPY
(SELECT * FROM tbl)
TO 'result-snappy.parquet'
(FORMAT parquet);
tbl을 zstd 압축 Parquet 파일로 쓰기:
COPY tbl
TO 'result-zstd.parquet'
(FORMAT parquet, COMPRESSION zstd);
tbl을 가장 빠른 압축을 제공하는 최저 압축 레벨로 zstd 압축 Parquet 파일에 쓰기:
COPY tbl
TO 'result-zstd.parquet'
(FORMAT parquet, COMPRESSION zstd, COMPRESSION_LEVEL 1);
key-value 메타데이터와 함께 Parquet 파일에 쓰기:
COPY (
SELECT
42 AS number,
true AS is_even
) TO 'kv_metadata.parquet' (
FORMAT parquet,
KV_METADATA {
number: 'Answer to life, universe, and everything',
is_even: 'not ''odd''' -- single quotes in values must be escaped
}
);
Parquet v2 파일로 쓰기:
COPY tbl
TO 'result-v2.parquet'
(FORMAT parquet, PARQUET_VERSION 'V2');
CSV 파일을 압축하지 않은 Parquet 파일로 쓰기:
COPY
'test.csv'
TO 'result-uncompressed.parquet'
(FORMAT parquet, COMPRESSION uncompressed);
zstd 압축과 row group 크기로 쿼리를 Parquet 파일에 쓰기:
COPY
(FROM generate_series(100_000))
TO 'row-groups-zstd.parquet'
(FORMAT parquet, COMPRESSION zstd, ROW_GROUP_SIZE 100_000);
데이터를 LZ4 압축 Parquet 파일에 쓰기:
COPY
(FROM generate_series(100_000))
TO 'result-lz4.parquet'
(FORMAT parquet, COMPRESSION lz4);
또는 동일하게:
COPY
(FROM generate_series(100_000))
TO 'result-lz4.parquet'
(FORMAT parquet, COMPRESSION lz4_raw);
데이터를 Brotli 압축 Parquet 파일에 쓰기:
COPY
(FROM generate_series(100_000))
TO 'result-brotli.parquet'
(FORMAT parquet, COMPRESSION brotli);
Parquet 파일의 딕셔너리 페이지 크기를 설정하려면 STRING_DICTIONARY_PAGE_SIZE_LIMIT 옵션을 써요 (기본값: 1 MB):
COPY
lineitem
TO 'lineitem-with-custom-dictionary-size.parquet'
(FORMAT parquet, STRING_DICTIONARY_PAGE_SIZE_LIMIT 100_000);
DuckDB의 EXPORT 명령으로 데이터베이스 전체를 일련의 Parquet 파일로 내보낼 수 있어요. 자세한 내용은 "EXPORT 문" 페이지를 참고하세요:
데이터베이스 전체의 테이블 내용을 Parquet으로 내보내기:
EXPORT DATABASE 'target_directory' (FORMAT parquet);
암호화
DuckDB는 암호화된 Parquet 파일의 읽기와 쓰기를 지원해요.
지원되는 기능
지원되는 Parquet 기능 목록은 Parquet 문서의 "Implementation status" 페이지에서 확인할 수 있어요.
Parquet 확장 설치와 로딩
Parquet 파일 지원은 확장(extension)을 통해 활성화됩니다. parquet 확장은 거의 모든 클라이언트에 번들로 포함되어 있어요. 하지만 클라이언트에 parquet 확장이 번들로 포함되어 있지 않다면 별도로 설치해야 합니다:
INSTALL parquet;