Parquet 형식
Parquet 형식
Parquet 형식은 Hadoop 생태계에서 널리 사용되는 Apache Parquet 컬럼형 저장 형식이에요. ClickHouse는 이 형식의 읽기와 쓰기를 지원합니다. Parquet 데이터 타입과 ClickHouse 데이터 타입 간의 매핑을 지원하며, GeoParquet 사양에 따른 geometry 컬럼 읽기·쓰기도 지원합니다.
출처: 문서
본문
| Input | Output | Alias |
|---|---|---|
| ✔ | ✔ |
설명 (Description)
Apache Parquet은 Hadoop 생태계에서 널리 퍼진 컬럼형 저장 형식입니다. ClickHouse는 이 형식의 읽기와 쓰기 연산을 지원합니다.
데이터 타입 매칭 (Data types matching)
아래 표는 Parquet 데이터 타입이 ClickHouse 데이터 타입과 어떻게 일치하는지 보여줍니다.
| Parquet type (logical, converted, or physical) | ClickHouse data type |
|---|---|
| BOOLEAN | Bool |
| UINT_8 | UInt8 |
| INT_8 | Int8 |
| UINT_16 | UInt16 |
| INT_16 | Int16 / Enum16 |
| UINT_32 | UInt32 |
| INT_32 | Int32 |
| UINT_64 | UInt64 |
| INT_64 | Int64 |
| DATE | Date32 |
| TIMESTAMP | DateTime64 |
| TIME | Time64 |
| FLOAT | Float32 |
| DOUBLE | Float64 |
| INT96 | DateTime64(9, ‘UTC’) |
| BYTE_ARRAY , UTF8 , ENUM , BSON | String |
| JSON | JSON |
| FIXED_LEN_BYTE_ARRAY | FixedString |
| DECIMAL | Decimal |
| LIST | Array |
| MAP | Map |
| struct | Tuple |
| FLOAT16 | Float32 |
| UUID | FixedString(16) |
| INTERVAL | FixedString(12) |
| Point (GeoParquet) | Point |
| MultiPoint (GeoParquet) | MultiPoint |
| LineString (GeoParquet) | LineString |
| Polygon (GeoParquet) | Polygon |
| MultiLineString (GeoParquet) | MultiLineString |
| MultiPolygon (GeoParquet) | MultiPolygon |
| mixed/unknown geometry (GeoParquet) | Geometry |
Parquet 파일을 쓸 때 일치하는 Parquet 타입이 없는 데이터 타입은 가장 가까운 사용 가능한 타입으로 변환됩니다:
| ClickHouse data type | Parquet type |
|---|---|
| IPv4 | UINT_32 |
| IPv6 | FIXED_LEN_BYTE_ARRAY (16 bytes) |
| Date (16 bits) | DATE (32 bits) |
| DateTime (32 bits, seconds) | TIMESTAMP (64 bits, milliseconds) |
| Int128/UInt128/Int256/UInt256 | FIXED_LEN_BYTE_ARRAY (16/32 bytes, little-endian) |
| Point | BYTE_ARRAY (WKB) + GeoParquet metadata |
| MultiPoint | BYTE_ARRAY (WKB) + GeoParquet metadata |
| LineString | BYTE_ARRAY (WKB) + GeoParquet metadata |
| Polygon | BYTE_ARRAY (WKB) + GeoParquet metadata |
| MultiLineString | BYTE_ARRAY (WKB) + GeoParquet metadata |
| MultiPolygon | BYTE_ARRAY (WKB) + GeoParquet metadata |
배열은 중첩될 수 있고 인자로 Nullable 타입의 값을 가질 수 있어요. Tuple과 Map 타입도 중첩될 수 있습니다.
넓은 정수 (Wide integers)
기본적으로 ClickHouse는 Int128, UInt128, Int256, UInt256을 little-endian 순서의 주석 없는 FIXED_LEN_BYTE_ARRAY(16/32) 값으로 기록합니다. 이 레거시 표현은 파일을 이전 ClickHouse 버전에서 읽을 수 있도록 기본값으로 유지됩니다.
대신 표준 Parquet DECIMAL 표현을 사용하려면 output_format_parquet_wide_integer_as_decimal = 1로 설정하세요:
| ClickHouse type | Parquet logical type | Physical type | Value encoding |
|---|---|---|---|
| UInt128 | DECIMAL(39, 0) | FIXED_LEN_BYTE_ARRAY(17) | 0 부호 바이트 다음에 16바이트 부호 없는 값을 big-endian 순서로 |
| UInt256 | DECIMAL(78, 0) | FIXED_LEN_BYTE_ARRAY(33) | 0 부호 바이트 다음에 32바이트 부호 없는 값을 big-endian 순서로 |
| Int128 | DECIMAL(39, 0) | FIXED_LEN_BYTE_ARRAY(17) | 16바이트 2의 보수 값을 big-endian 순서로, 17바이트로 부호 확장 |
| Int256 | DECIMAL(77, 0) | FIXED_LEN_BYTE_ARRAY(33) | 32바이트 2의 보수 값을 big-endian 순서로, 33바이트로 부호 확장 |
소수 표현은 표준 Parquet 컬럼 청크 통계와 페이지 인덱스에 숫자 순서를 제공하므로, ClickHouse가 row-group과 페이지 min/max 프루닝을 사용할 수 있습니다. ClickHouse는 두 인코딩을 모두 읽습니다. 소수 정밀도 39의 경우 스키마 추론은 Decimal256을 기반으로 하는 Decimal(39, 0)을 반환합니다. 명시적 Int128 또는 UInt128 구조를 지정하여 넓은 정수 타입을 복구할 수 있어요. 소수 정밀도 77 또는 78은 ClickHouse Decimal256의 범위를 초과하므로 해당 파일을 읽으려면 명시적 호환 Int256 또는 UInt256 구조가 필요합니다. 명시적 넓은 정수 구조로 ClickHouse는 BYTE_ARRAY 또는 FIXED_LEN_BYTE_ARRAY로 저장된 모든 유효한 너비의 표준 소수 값을 허용하고, 부호 확장을 제거한 후 각 값을 범위 검사합니다.
일부 Parquet 클라이언트는 소수 정밀도 최대 38까지만 지원하고, Arrow의 고수준 소수 타입은 최대 76까지만 지원합니다. 그러한 클라이언트는 스키마와 33바이트 물리적 너비가 Parquet을 따르더라도 정밀도 77/78 표현을 거부할 수 있어요. 더 작은 소수 한계를 가진 구형 ClickHouse 버전이나 클라이언트로 파일을 읽어야 할 때는 설정을 비활성화 상태로 유지하세요.
ClickHouse 테이블 컬럼의 데이터 타입은 삽입되는 Parquet 데이터의 해당 필드와 다를 수 있어요. 데이터를 삽입할 때 ClickHouse는 위 표에 따라 데이터 타입을 해석한 다음 ClickHouse 테이블 컬럼에 설정된 데이터 타입으로 캐스팅합니다. 예를 들어 UINT_32 Parquet 컬럼을 IPv4 ClickHouse 컬럼으로 읽을 수 있습니다.
일부 Parquet 타입에는 밀접하게 일치하는 ClickHouse 타입이 없습니다. 우리는 그것들을 다음과 같이 읽습니다:
isAdjustedToUTC=false인TIMESTAMP는 로컬 벽시계 시간입니다(어떤 특정 시간대가 로컬로 간주되는지와 무관하게 로컬 시간대의 연, 월, 일, 시, 분, 초 및 서브초 필드). SQLTIMESTAMP WITHOUT TIME ZONE과 동일합니다. ClickHouse는 그것을 UTC 타임스탬프인 것처럼 읽습니다. 예:2025-09-29 18:42:13.000(로컬 벽시계 판독값을 나타냄)은2025-09-29 18:42:13.000(DateTime64(3, 'UTC')는 시점을 나타냄)이 됩니다. String으로 변환하면 올바른 연, 월, 일, 시, 분, 초 및 서브초를 표시하며, 이는 UTC 대신 일부 로컬 시간대에 있는 것으로 해석될 수 있습니다. 직관에 반하여, 타입을DateTime64(3, 'UTC')에서DateTime64(3)으로 변경해도 도움이 되지 않습니다. 두 타입 모두 시계 판독값이 아닌 시점을 나타내지만DateTime64(3)은 로컬 시간대를 사용하여 잘못 형식화될 것이기 때문입니다.INTERVAL은 현재 Parquet 파일에 인코딩된 시간 간격의 원시 바이너리 표현으로FixedString(12)로 읽힙니다.
Geo 타입 (Geo types, GeoParquet)
ClickHouse는 GeoParquet 사양에 따른 geometry 컬럼의 읽기와 쓰기를 지원합니다. Geometry 컬럼은 WKB(읽을 때는 WKT)로 인코딩된 BYTE_ARRAY 페이로드로 저장되며, 각 geometry 컬럼의 인코딩, geometry 타입, CRS를 설명하는 JSON geo 키가 파일 수준 Parquet 메타데이터에 있습니다.
읽기 동작 (Read behavior)
읽을 때 geometry 컬럼은 해당 ClickHouse geo 데이터 타입으로 매핑됩니다:
Point,MultiPoint,LineString,Polygon,MultiLineString또는MultiPolygon으로 선언된 컬럼은 일치하는 ClickHouse geo 타입으로 읽힙니다.- 여러 개 또는 알 수 없는 geometry 타입을 가진 컬럼은 Geometry 타입으로 읽히며, 이는 모든 지원 geo 타입에 대한
Variant입니다. - 요청된 컬럼 타입이
String이면 GeoParquet 메타데이터는 무시되고 원시 인코딩된 geometry 페이로드가 그대로 반환됩니다 — GeoParquet 컬럼이 선언하는 인코딩에 따라 WKB 또는 WKT 바이트. input_format_parquet_allow_geoparquet_parser 설정이0으로 설정된 경우에도 마찬가지입니다.
쓰기 동작 (Write behavior)
쓸 때 Point, MultiPoint, LineString, Polygon, MultiLineString, MultiPolygon 타입의 최상위 컬럼은 BYTE_ARRAY(WKB)로 인코딩되고 적절한 geo JSON 메타데이터가 Parquet 파일 푸터에 추가됩니다. 최상위 Geometry Variant도 WKB BYTE_ARRAY 페이로드로 인코딩되지만(하위 값은 WKB로 변환되어 Nullable(String) 컬럼으로 저장됨) geo 메타데이터는 출력되지 않아서, 읽을 때 GeoParquet geometry 컬럼으로 인식되지 않습니다. Ring과 같은 다른 geo 관련 타입은 GeoParquet 메타데이터 없이 네이티브 기본 표현으로 기록됩니다. 이 동작은 output_format_parquet_geometadata를 0으로 설정하면 완전히 비활성화할 수 있으며, 이 경우 지원되는 geo 타입조차 네이티브 기본 표현(Point는 Tuple(Float64, Float64), LineString은 Array(Point), Polygon은 Array(Array(Point)) 등)으로 기록되고 GeoParquet 메타데이터는 출력되지 않습니다.
Geometry 컬럼은 스키마의 루트 또는 Tuple(struct) 내부에 중첩되어야 합니다. Array 또는 Map 내부에 중첩하는 것은 지원되지 않습니다. geo 컬럼에는 Nullable도 지원되지 않습니다.
사용 예시 (Example usage)
데이터 삽입 (Inserting data)
football.parquet라는 이름의 Parquet 파일에 다음 데이터가 있다고 가정해 볼게요:
┌───────date─┬─season─┬─home_team─────────────┬─away_team───────────┬─home_team_goals─┬─away_team_goals─┐
1. │ 2022-04-30 │ 2021 │ Sutton United │ Bradford City │ 1 │ 4 │
2. │ 2022-04-30 │ 2021 │ Swindon Town │ Barrow │ 2 │ 1 │
3. │ 2022-04-30 │ 2021 │ Tranmere Rovers │ Oldham Athletic │ 2 │ 0 │
4. │ 2022-05-02 │ 2021 │ Port Vale │ Newport County │ 1 │ 2 │
5. │ 2022-05-02 │ 2021 │ Salford City │ Mansfield Town │ 2 │ 2 │
6. │ 2022-05-07 │ 2021 │ Barrow │ Northampton Town │ 1 │ 3 │
7. │ 2022-05-07 │ 2021 │ Bradford City │ Carlisle United │ 2 │ 0 │
8. │ 2022-05-07 │ 2021 │ Bristol Rovers │ Scunthorpe United │ 7 │ 0 │
9. │ 2022-05-07 │ 2021 │ Exeter City │ Port Vale │ 0 │ 1 │
10. │ 2022-05-07 │ 2021 │ Harrogate Town A.F.C. │ Sutton United │ 0 │ 2 │
11. │ 2022-05-07 │ 2021 │ Hartlepool United │ Colchester United │ 0 │ 2 │
12. │ 2022-05-07 │ 2021 │ Leyton Orient │ Tranmere Rovers │ 0 │ 1 │
13. │ 2022-05-07 │ 2021 │ Mansfield Town │ Forest Green Rovers │ 2 │ 2 │
14. │ 2022-05-07 │ 2021 │ Newport County │ Rochdale │ 0 │ 2 │
15. │ 2022-05-07 │ 2021 │ Oldham Athletic │ Crawley Town │ 3 │ 3 │
16. │ 2022-05-07 │ 2021 │ Stevenage Borough │ Salford City │ 4 │ 2 │
17. │ 2022-05-07 │ 2021 │ Walsall │ Swindon Town │ 0 │ 3 │
└────────────┴────────┴───────────────────────┴─────────────────────┴─────────────────┴─────────────────┘
데이터를 삽입합니다:
INSERT INTO football FROM INFILE 'football.parquet' FORMAT Parquet;
데이터 읽기 (Reading data)
Parquet 형식을 사용하여 데이터를 읽습니다:
SELECT *
FROM football
INTO OUTFILE 'football.parquet'
FORMAT Parquet
Parquet는 터미널에서 사람이 읽을 수 있는 형태로 표시되지 않는 바이너리 형식입니다. Parquet 파일을 출력하려면 INTO OUTFILE을 사용하세요. Hadoop과 데이터를 교환하려면 HDFS 테이블 엔진을 사용할 수 있어요.
형식 설정 (Format settings)
| Setting | Description | Default |
|---|---|---|
| input_format_parquet_case_insensitive_column_matching | Parquet 컬럼을 CH 컬럼과 매칭할 때 대소문자 무시. | 0 |
| input_format_parquet_preserve_order | Parquet 파일을 읽을 때 행 재정렬 방지. 일반적으로 훨씬 느림. | 0 |
| input_format_parquet_filter_push_down | Parquet 파일을 읽을 때 WHERE/PREWHERE 표현식과 Parquet 메타데이터의 min/max 통계를 기반으로 전체 row group 건너뛰기. | 1 |
| input_format_parquet_bloom_filter_push_down | Parquet 파일을 읽을 때 WHERE 표현식과 Parquet 메타데이터의 bloom filter를 기반으로 전체 row group 건너뛰기. | 0 |
| input_format_parquet_dictionary_filter_push_down | Parquet 파일을 읽을 때(reader v3 사용) WHERE/PREWHERE 표현식과 딕셔너리 페이지 내용을 기반으로 컬럼 청크의 모든 데이터 페이지가 딕셔너리 인코딩된 경우 동등 및 IN 조건에 대해 전체 row group 건너뛰기. 값은 이 최적화가 적용되는 최대 딕셔너리 페이지 크기(바이트). 0으로 설정하면 비활성화. 둘 다 사용 가능할 때 bloom filter보다 우선. | 1048576 |
| input_format_parquet_allow_missing_columns | Parquet 입력 형식을 읽을 때 누락된 컬럼 허용 | 1 |
| input_format_parquet_local_file_min_bytes_for_seek | Parquet 입력 형식에서 무시하며 읽는 대신 seek을 수행하기 위해 로컬 읽기(파일)에 필요한 최소 바이트 | 8192 |
| input_format_parquet_enable_row_group_prefetch | parquet 파싱 중 row group 프리페치 활성화. 현재 단일 스레드 파싱만 프리페치 가능. | 1 |
| input_format_parquet_skip_columns_with_unsupported_types_in_schema_inference | Parquet 형식의 스키마 추론 중 지원되지 않는 타입의 컬럼 건너뛰기 | 0 |
| input_format_parquet_max_block_size | parquet 리더의 최대 블록 크기. | 65409 |
| input_format_parquet_prefer_block_bytes | parquet 리더가 출력하는 평균 블록 바이트 | 16744704 |
| input_format_parquet_enable_json_parsing | Parquet 파일을 읽을 때 JSON 컬럼을 ClickHouse JSON Column으로 파싱. | 1 |
| input_format_parquet_allow_geoparquet_parser | Parquet 파일을 읽을 때 GeoParquet geo 메타데이터를 인식하고 geometry 컬럼(컬럼의 선언된 인코딩에 따라 WKB 또는 WKT)을 ClickHouse geo 데이터 타입으로 디코딩. 0 이면 geometry 컬럼이 원시 물리적( String ) 표현으로 노출됨. | 1 |
| output_format_parquet_row_group_size | 행 단위의 대상 row group 크기. | 1000000 |
| output_format_parquet_row_group_size_bytes | 압축 전 바이트 단위의 대상 row group 크기. | 536870912 |
| output_format_parquet_string_as_string | String 컬럼에 Binary 대신 Parquet String 타입 사용. | 1 |
| output_format_parquet_fixed_string_as_fixed_byte_array | FixedString 컬럼에 Binary 대신 Parquet FIXED_LEN_BYTE_ARRAY 타입 사용. | 1 |
| output_format_parquet_wide_integer_as_decimal | Int128 , UInt128 , Int256 , UInt256 을 레거시 little-endian 고정 바이트 배열 대신 표준 big-endian Parquet DECIMAL 값으로 기록. | 0 |
| output_format_parquet_compression_method | Parquet 출력 형식의 압축 방법. 지원 코덱: snappy, lz4, brotli, zstd, gzip, none (압축 안 함) | zstd |
| output_format_parquet_parallel_encoding | Parquet 인코딩을 여러 스레드로 수행. | 1 |
| output_format_parquet_data_page_size | 압축 전 바이트 단위의 대상 페이지 크기. | 1048576 |
| output_format_parquet_batch_size | 이 행 수마다 페이지 크기 확인. 평균 값 크기가 몇 KB를 넘는 컬럼이 있으면 줄이는 것을 고려. | 1024 |
| output_format_parquet_write_page_index | parquet 파일에 페이지 인덱스 기록 가능성 추가. | 1 |
| output_format_parquet_geometadata | Parquet 파일 푸터에 GeoParquet geo 메타데이터를 기록하고 최상위 ClickHouse geo 컬럼( Point , MultiPoint , LineString , Polygon , MultiLineString , MultiPolygon )을 WKB로 인코딩. 0 이면 해당 컬럼을 네이티브 기본 표현(예: Point는 Tuple(Float64, Float64) )으로 기록하고 GeoParquet 메타데이터는 출력하지 않음. | 1 |
| input_format_parquet_import_nested | 더 이상 사용되지 않는 설정, 아무것도 하지 않음. | 0 |
| input_format_parquet_local_time_as_utc | true | isAdjustedToUTC=false인 Parquet 타임스탬프에 대한 스키마 추론에서 사용되는 데이터 타입을 결정. true이면: DateTime64(…, ‘UTC’), false이면: DateTime64(…). ClickHouse에는 로컬 벽시계 시간 데이터 타입이 없으므로 어느 쪽도 완전히 올바르지 않음. 직관에 반하여 ‘true’가 아마 덜 잘못된 선택인데, 그 이유는 ‘UTC’ 타임스탬프를 String으로 형식화하면 올바른 로컬 시간 표현이 생성되기 때문. |