Skip to content

필사 모드: Parquet 2.13.0의 nan_count와 IEEE 754 total order — float 통계가 3년 3개월 만에 고쳐진 이야기

한국어
0%
정확도 0%
💡 왼쪽 원문을 읽으면서 오른쪽에 따라 써보세요. Tab 키로 힌트를 받을 수 있습니다.

들어가며 — 통계는 스킵하려고 있는 건데, float에서는 그게 안 됐다

Parquet 파일이 빠른 이유의 큰 몫은 통계입니다. 로우 그룹마다, 컬럼 청크마다, 페이지마다 min, max, null_count 같은 요약을 적어 두고, 쿼리 엔진은 그 요약만 보고 "이 덩어리에는 답이 없다"고 판단해 통째로 건너뜁니다. 프레디킷 푸시다운과 페이지 프루닝이 이 위에 서 있습니다. 컬럼 지향 스토리지의 전체 그림은 컬럼 지향 스토리지 완전 가이드 편에 정리해 뒀습니다.

정수나 문자열에서는 이 계약이 단순합니다. writer가 진짜 최솟값과 최댓값을 적고, reader가 그 범위로 판단하면 됩니다. 그런데 FLOAT, DOUBLE 컬럼에서는 이 단순한 모델이 무너집니다. 그것도 "조금 느려지는" 방식이 아니라 쿼리가 있는 행을 못 찾는 방식으로 무너집니다.

2026년 6월 13일 릴리스된 parquet-format 2.13.0이 이 구멍을 스펙 차원에서 막았습니다. 이 글은 그 변경이 정확히 무엇이고, 왜 3년 넘게 걸렸고, 지금 실제로 쓸 수 있는 상태인지를 봅니다.

왜 float 통계만 유독 어려운가

이유는 두 가지입니다. Parquet 커뮤니티가 낸 공식 블로그 글(Jan Finis, Gang Wu, 2026-05-29)이 이 둘을 정리해 놓았습니다.

첫째, 부호 있는 0. -0.0+0.0은 일반 연산에서 같다고 취급되지만 비트 패턴은 다릅니다. 순서를 규정하지 않으면 라이브러리마다 같은 데이터에서 서로 다른 통계를 내놓습니다. Parquet이 그동안 쓴 방편은 우회였습니다 — 최솟값이 0.0이면 실제 부호와 무관하게 무조건 -0.0으로, 최댓값이 0.0이면 무조건 +0.0으로 적으라고 강제한 것입니다. 그리고 reader에게는 "min이 +0.0이어도 -0.0이 들어 있을 수 있다"고 경고합니다. 정렬이 아니라 방어입니다.

둘째, NaN. 이쪽이 진짜 문제입니다. IEEE 754에서 NaN은 순서가 아예 없습니다. x < NaN도, x > NaN도, x == NaN도 전부 false입니다. writer가 NaN을 그냥 min/max 계산에 넣으면 나온 경계는 아무 쓸모가 없습니다. 그래서 Parquet은 반대 방향을 택했습니다 — NaN을 통계에서 배제한다.

여기서 사고가 납니다. 블로그 글의 예를 그대로 옮기면 이렇습니다. 어떤 페이지의 max 통계가 0.0인데 그 페이지에 NaN이 하나 들어 있다고 합시다. NaN을 모든 값보다 크다고 취급하는 쿼리 엔진이 x > 1.0 같은 프레디킷을 던집니다. 엔진이 통계를 보면 max가 0.0이니, 조건을 만족하는 행이 실제로 들어 있는데도 그 페이지를 부당하게 건너뛸 수 있습니다. 원문의 표현대로, NaN의 존재 여부를 모르는 상태에서 엔진은 부동소수점 컬럼에 대해 이런 종류의 페이지 프루닝을 안전하게 수행할 수 없습니다.

즉 통계가 "NaN을 뺀 범위"인데 reader는 그 사실을 알 방법이 없었습니다. nan_count가 없었으니까요.

이건 이론이 아니다 — DataFusion에서 지금도 재현된다

추상적으로 들린다면, 실제 재현 케이스가 있습니다. DataFusion 이슈 #15812 "Pruning of floating point Parquet columns is incorrect when NaN is present"는 2025년 4월 22일에 올라와 오늘(2026-07-16)까지도 열려 있습니다.

이슈 본문이 든 예는 이렇습니다. 컬럼이 [1.0, 0.0, -1.0, NaN, -2.0]이면 max는 1, min은 -2로 잡힙니다(NaN 배제). 그런데 select * from ... where x > 2를 던지면 max > 2인 청크가 없으므로 결과가 0행입니다. DataFusion은 NaN을 2보다 크다고 보므로, 정답은 NaN 한 행이어야 합니다.

이슈에 붙은 재현은 parquet-testing 저장소의 실제 파일을 씁니다.

> select * from 'parquet-testing/data/float16_nonzeros_and_nans.parquet' where x > arrow_cast(2.0, 'Float16');
+---+
| x |
+---+
+---+
0 row(s) fetched.

기대값은 NaN이 든 한 행입니다. 그리고 그 파일은 지금도 저장소에 있습니다.

문제를 더 어렵게 만드는 건 엔진들이 NaN 비교에 합의하지 못한다는 점입니다. arrow-rs 추적 이슈 #8156에서 alamb이 붙인 실행 결과를 보면, DataFusion은 같은 데이터에서 NaN > 34를 true로, -NaN > 34를 false로 판정하는데(arrow-rs가 부동소수점 비교에 총 순서를 쓰기 때문입니다), PostgreSQL은 둘 다 true를 냅니다. 같은 스레드에서 tustvold는 이렇게까지 말합니다 — 구현체 중 버그 있는 게 너무 많아서(그의 표현으로는 arrow-rs의 과거 버전들 포함) DataFusion은 부동소수점 프레디킷을 아예 푸시다운하지 말아야 하며, 하고 있다면 그건 고쳐야 할 버그라고요.

이게 스펙을 고쳐야 했던 이유입니다. 각 엔진이 알아서 잘하는 걸로는 안 되는 문제였습니다.

PARQUET-2249 — ColumnIndex가 처한 불가능한 요구

문제의 이름은 PARQUET-2249입니다. 제목은 "Parquet spec (parquet.thrift) is inconsistent w.r.t. ColumnIndex + NaNs"이고, 2023년 2월 19일 Jan Finis가 올렸습니다.

핵심은 이렇습니다. 어떤 데이터 페이지가 전부 NaN이라고 해 봅시다. 이 페이지는 "null 페이지"가 아닙니다 — 데이터는 물리적으로 거기 있고, NaN은 결측(null)과 다릅니다. 그런데 기존 지침은 min/max 계산에서 NaN을 빼라고 합니다. 한편 ColumnIndex는 null이 아닌 페이지라면 유효한 min_valuesmax_valuesrequired로 요구합니다. 쓸 수 있는 non-NaN 값이 하나도 없는데 반드시 써야 하는 상황 — 스펙 안에서 모순이 닫히지 않습니다.

Statistics 쪽이라면 num_values, null_count, nan_count를 조합해 "non-null이 전부 NaN"임을 유도할 수 있습니다. 그런데 ColumnIndex에는 num_values 필드가 없습니다. 2.13.0의 parquet.thrift를 직접 읽어 보면 ColumnIndex의 필드는 null_pages, min_values, max_values, boundary_order, null_counts, 레벨 히스토그램들, 그리고 새로 붙은 nan_counts뿐입니다. 그 산수를 여기서는 할 수가 없습니다.

3년 3개월 — 두 번의 무산, 그리고 합의

여기서부터가 이 이야기의 재미있는 부분입니다. 해법이 한 번에 나오지 않았습니다.

  • 2023-02-19 — PARQUET-2249 등록(Jan Finis).
  • 2023-03-22PR #196 "Add nan_count to statistics". 통계에 nan_count를 추가하자는 안. NaN 존재 여부를 명시적으로 알려 주고, 옵셔널 필드라 구 reader를 깨지 않는 안전한 마이그레이션 경로였습니다. 코멘트 99개(일반 31 + 리뷰 68)를 남기고 머지되지 않은 채 닫혔습니다. ColumnIndex 딜레마를 못 풀었기 때문입니다.
  • 2023-11-22PR #221 "Introduce IEEE 754 total order". 아예 새 컬럼 순서를 도입하는 안. 부호 있는 0과 NaN 비트 패턴에 결정론적 자리를 주는 대신, 치명적 약점이 있었습니다 — NaN이 총 순서의 양 끝에 놓이므로 NaN 하나만 있어도 min이나 max가 오염되어 일반적인 수치 프레디킷 푸시다운이 완전히 무력해집니다. 코멘트 52개를 남기고 역시 머지되지 않았습니다.
  • 2025-04-22 — DataFusion #15812 등록. 스펙 논의가 도는 동안 실제 엔진의 오답으로 나타납니다.
  • 2025-08-09PR #514 "PARQUET-2249: Introduce IEEE 754 total order & NaN-counts". 둘을 합칩니다.
  • 2026-05-26 — PR #514 머지. 열린 지 약 9개월 반, 코멘트 67개(일반 17 + 리뷰 50), 순 변경은 3개 파일에 98줄 추가 / 6줄 삭제.
  • 2026-06-13 — parquet-format 2.13.0 릴리스.

이슈 등록부터 스펙 머지까지 3년 3개월입니다. 최종 변경이 98줄이라는 걸 생각하면, 이 프로젝트에서 어려웠던 건 코드가 아니라 합의였다는 게 분명합니다.

합의의 논리는 이렇습니다. 새 총 순서는 경계를 어떻게 비교할지 엄격히 정의하고, nan_count는 NaN의 존재를 명시적으로 표시합니다. 그리고 결정적으로 — 기존 writer 중 새 순서를 쓰는 것은 하나도 없으므로, 스펙은 IEEE_754_TOTAL_ORDER를 쓸 때 nan_count의무화해도 안전합니다. 구 파일은 구 파일대로 관대하게 처리하면서요. 깨끗한 백지를 새로 하나 만든 셈입니다.

2.13.0이 스펙에서 정확히 바꾼 것

말이 아니라 IDL을 보는 게 빠릅니다. 2.12.0의 parquet.thrift에는 nan_countIEEE754TotalOrder존재하지 않습니다(문자열 검색 결과 0건). 2.13.0에서 새로 생긴 것은 셋입니다.

첫째, Statistics에 9번 필드가 붙었습니다.

   /**
    * Count of NaN values in the column; only present if physical type is FLOAT
    * or DOUBLE, or logical type is FLOAT16.
    * If this field is not present, readers MUST assume NaNs may be present
    * (i.e. MUST assume nan_count > 0 and MAY NOT assume nan_count == 0).
    */
   9: optional i64 nan_count;

여기서 중요한 건 마지막 문장입니다. 필드가 없는 것0인 것은 다릅니다. 없으면 "모른다"이고, reader는 NaN이 있을 수 있다고 가정해야 합니다. 이 규칙이 없으면 구 파일이 전부 "NaN 없음"으로 오독됩니다.

둘째, ColumnIndex에 페이지별 리스트가 붙었습니다.

   /**
    * A list containing the number of NaN values for each page. Only present
    * for columns of physical type FLOAT or DOUBLE, or logical type FLOAT16.
    * If this field is not present, readers MUST assume that there might be
    * NaN values in any page.
    */
   8: optional list<i64> nan_counts

셋째, ColumnOrder union에 새 변형이 생겼습니다.

/** Empty struct to signal IEEE 754 total order for floating point types */
struct IEEE754TotalOrder {}

union ColumnOrder {
  1: TypeDefinedOrder TYPE_ORDER;
  2: IEEE754TotalOrder IEEE_754_TOTAL_ORDER;
}

새 순서의 의미는 스펙에 이렇게 적혀 있습니다 — IEEE-754(2008 개정) 5.10절의 totalOrder 술어를 따르며, FLOAT, DOUBLE, 또는 논리 타입 FLOAT16 컬럼만 이 순서를 쓸 수 있습니다. 직관적으로는 부동소수점을 수학적 순서로 정렬하되 -0+0보다 작게, -NaN을 그 무엇보다 작게, +NaN을 그 무엇보다 크게 놓고, 같은 값의 서로 다른 비트 표현 사이에도 순서를 정의합니다.

그리고 IEEE_754_TOTAL_ORDER를 쓰면 nan_count 기록이 의무입니다. min/max는 non-NaN 값 중 최소·최대를 담되, non-null 값이 전부 NaN이면 총 순서상 최소·최대 NaN으로 폴백합니다 — 이게 PARQUET-2249의 그 불가능한 요구를 푸는 지점입니다. ColumnIndex에는 num_values가 없으니, 대신 min_valuesmax_values에 NaN이 나타나는 것 자체가 "이 페이지는 전부 NaN"이라는 신호가 됩니다.

기존 TYPE_ORDER도 그냥 버려지지 않았습니다. 2.13.0은 TYPE_ORDER에 대해 "float 타입은 NaN과 -0/+0 처리가 underspecified라 모호하므로 writer는 IEEE_754_TOTAL_ORDER를 쓰는 것을 권장한다"고 적고, 그래도 쓸 거라면 nan_count를 (0이더라도) 반드시 적고 min/max는 non-NaN 값으로만 계산하라는 규칙을 새로 명시했습니다. 2.12.0에서 "should"였던 것이 상당수 "must"로 조여졌습니다.

총 순서 구현은 의외로 한 줄이다

이름이 거창해서 무거운 비교 엔진이 필요할 것 같지만 아닙니다. 공식 블로그가 제시한 Rust 스케치는 이렇습니다.

pub fn totalOrder(x: f64, y: f64) -> bool {
    let mut x_int = x.to_bits() as i64;
    let mut y_int = y.to_bits() as i64;
    x_int ^= (((x_int >> 63) as u64) >> 1) as i64;
    y_int ^= (((y_int >> 63) as u64) >> 1) as i64;
    return x_int <= y_int;
}

IEEE 비트 패턴을 보존한 채, 음수만 뒤집어서 정수 표현이 올바른 순서로 정렬되게 만들고, 그냥 정수로 비교하는 트릭입니다. 32비트 float도 같습니다.

그리고 실제 구현이 정말 그렇게 돼 있습니다. parquet-java의 PrimitiveComparator를 열어 보면 동일한 트릭입니다.

public int compare(double d1, double d2) {
  long d1Long = Double.doubleToRawLongBits(d1);
  long d2Long = Double.doubleToRawLongBits(d2);
  d1Long ^= ((d1Long >> 63) >>> 1);
  d2Long ^= ((d2Long >> 63) >>> 1);
  return Long.compare(d1Long, d2Long);
}

doubleToLongBits가 아니라 doubleToRawLongBits라는 게 포인트입니다. 앞의 것은 NaN을 정규화해 버리고, 뒤의 것은 NaN의 부호와 페이로드 비트를 그대로 보존합니다. 총 순서가 "같은 값의 서로 다른 비트 표현 사이에도 순서를 정의"하려면 raw여야 합니다.

지금 구현 상태 — 스펙은 났고, 엔진은 아직

여기가 이 글에서 가장 정직해야 할 부분입니다. 스펙이 릴리스됐다고 여러분의 파이프라인이 고쳐지지는 않습니다. 2026년 7월 16일 기준 각 구현체를 직접 확인한 결과입니다.

parquet-java — 구현됐지만 릴리스 전. PR #3393 "PARQUET-2249: Add IEEE-754 total order and nan count for floating types"가 wgtmac(공식 블로그 공동 저자 Gang Wu)에 의해 2026년 2월 12일 열려 2026년 6월 25일 머지됐습니다. 규모는 40개 파일에 4,857줄 추가 / 229줄 삭제입니다. IEEE754FloatStatistics, IEEE754DoubleStatistics, IEEE754Float16Statistics 같은 실제 클래스와 TestIeee754TotalOrderE2E 같은 E2E 테스트가 들어 있고, pom.xmlparquet.format.version은 이미 2.13.0입니다. 다만 parquet-java의 최신 릴리스는 1.17.1(2026-05-12) — 머지보다 앞섭니다. 즉 지금 Maven에서 받는 버전에는 없습니다.

Arrow C++ — thrift만 동기화. 2026년 6월 29일 커밋 "GH-50265: [C++][Parquet] Update parquet.thrift to sync with 2.13.0"으로 cpp/src/parquet/parquet.thrift가 2.13.0을 따라갔고, 생성된 parquet_types.h 등에도 필드가 들어왔습니다. 그런데 실제 통계를 계산하는 cpp/src/parquet/statistics.cc에는 nan_count 언급이 0건입니다. 와이어 포맷 정의는 있는데 그걸 채우거나 읽는 로직은 없는 상태입니다.

arrow-rs / DataFusion — 아직 draft. PR #9619 "Implement PARQUET-2249: Introduce IEEE 754 total order"가 etseidl에 의해 2026년 3월 26일 열려 지금도 draft입니다(17개 파일, 1,545줄 추가 / 252줄 삭제, 코멘트 106개, 최종 업데이트 2026-07-14 — 활발히 진행 중입니다). 앞선 시도들 — Xuanwo의 #8158은 2026년 7월 4일 머지 없이 닫혔고, PoC였던 #7408과 #9669도 머지되지 않았습니다. 현재 main의 손으로 쓴 thrift 디코더(parquet/src/file/metadata/thrift/mod.rs)를 검색하면 nan_count는 0건이고, basic.rsColumnOrder enum이 아는 것은 TYPE_DEFINED_ORDER, UNDEFINED, UNKNOWN뿐입니다. 즉 Rust parquet 크레이트 최신 릴리스(59.1.0, 2026-07-07)에는 들어 있지 않습니다.

정리하면 — 스펙은 6월 13일에 났고, 한 달이 지난 지금 어떤 메이저 구현체의 릴리스에도 이 기능이 들어 있지 않습니다. parquet-java가 가장 앞서 있고 다음 릴리스에 실릴 가능성이 높지만, 그것도 아직 나오지 않았습니다.

정직한 비용 — 이 수정은 공짜가 아니다

"오래된 버그가 고쳐졌다"는 이야기는 보통 순수한 좋은 소식으로 들립니다. 이번 건은 아닙니다.

옵트인이다. parquet-java PR #3393의 본문이 명시합니다 — "The existing type-defined order remains the default."(기존 type-defined order가 여전히 기본값입니다.) 코드를 봐도 PrimitiveTypecolumnOrder가 지정되지 않으면 ColumnOrder.typeDefined()로 떨어집니다. 컬럼 단위로 스키마에서 켜야 합니다. 아무것도 안 하면 아무것도 안 바뀝니다.

프루닝이 오히려 보수적으로 바뀐다. 같은 PR 본문의 문장을 그대로 옮기면, "Filtering around NaN values may be more conservative to avoid dropping data that can still match."(매칭될 수 있는 데이터를 버리지 않기 위해, NaN 주변의 필터링이 더 보수적으로 동작할 수 있습니다.) 이건 트레이드오프의 본질입니다 — 지금까지의 "빠름"은 일부 틀린 답 위에 서 있었고, 정답을 보장하는 순간 일부 쿼리는 덜 스킵하게 됩니다. nan_count가 0이 아니면 col > 34 같은 프레디킷은 통계만으로 푸시다운할 수 없습니다. arrow-rs 스레드에서 tustvold가 지적한 그대로입니다. 얼마나 느려지는지에 대한 측정치는 어느 소스에도 공개돼 있지 않으므로, 여기서 숫자를 만들지는 않겠습니다.

블라스트 반경이 스펙 98줄보다 훨씬 크다. parquet-java 쪽 40개 파일에 무엇이 들어 있는지 보면 감이 옵니다 — 통계와 컬럼 인덱스뿐 아니라 DictionaryValuesWriter, ByteStreamSplitValuesWriter, BloomFilterImpl, DictionaryFilter, StatisticsFilter, 심지어 LittleEndianDataOutputStream까지 건드렸습니다. PR 본문에 따르면 이는 NaN의 부호·페이로드 비트를 애플리케이션이 준 그대로 보존하기 위해서입니다. 뒤집어 말하면 parquet-java가 그동안 NaN 비트 패턴을 보존하지 않았다는 뜻이기도 합니다.

구 reader 호환은 이론과 실제가 다르다. 스펙은 "reader가 이 union의 값을 지원하지 않으면 해당 컬럼의 min/max 통계는 무시해야 한다"고 적어 두었고, arrow-rs 현재 main은 실제로 모르는 union 변형을 ColumnOrder::UNKNOWN으로 떨어뜨리고 통계를 무시합니다 — 스펙대로입니다. 그런데 arrow-rs 이슈 #8156에서 emkornfield가 2026년 5월 19일에 제기한 우려는 이겁니다. 구 릴리스(그의 표현으로는 "I think prior to arrow 57")는 생성된 thrift 코드를 쓰는데, 새 파일을 읽을 때 파서가 패닉할 수 있으니 백포트가 필요하지 않냐는 것입니다. etseidl의 답은 문제가 크레이트 코드가 아니라 Rust thrift 제너레이터에 있다는 것이었고, alamb은 "누군가 실제로 원한다는 증거가 생기면 그때 백포트하자"고 답했습니다. 어느 쪽이든 — 스펙이 옵셔널 필드와 union 확장으로 "안전하게" 설계됐어도, 필드를 추가하는 것과 순서 union에 변형을 추가하는 것의 호환성 성질은 다릅니다. 전자는 구 reader가 무시하면 그만이고, 후자는 구 reader가 그걸 어떻게 다루는지에 달려 있습니다.

그래서 지금 뭘 해야 하나

당장 할 것: 여러분의 float 프레디킷이 이미 틀리고 있는지 확인. 이건 미래의 문제가 아니라 현재의 문제입니다. NaN이 들어갈 수 있는 float 컬럼에 > / < 프레디킷을 던지고 있고, 엔진이 통계 기반 프루닝을 한다면, DataFusion #15812와 같은 종류의 오답 가능성이 있습니다. 판단 기준은 단순합니다 — 그 컬럼에 NaN이 실제로 들어갈 수 있는가. 센서 데이터, 결측을 NaN으로 표현하는 과학 계산 파이프라인, 0으로 나눈 결과가 흘러드는 집계 — 이런 곳이 후보입니다. NaN이 원리상 들어갈 수 없는 컬럼이라면 이 글 전체가 여러분과 무관합니다.

켜지 말아야 할 때: 지금 대부분의 경우. 어떤 릴리스에도 없으니 켤 수가 없다는 게 첫 번째 이유입니다. 두 번째는 상호운용성입니다. 새 컬럼 순서로 쓴 파일은 그 순서를 이해하는 reader가 있어야 통계를 활용할 수 있고, 아직은 거의 없습니다. 지금 이걸 켜서 얻는 것은 "미래에 유효해질 메타데이터"이고, 그동안 치르는 값은 구 reader와의 미검증 상호작용입니다. 그래서 parquet-testing 저장소에 상호운용 테스트 파일을 넣고 parquet-java가 TestInterOpReadFloatingPointNanCount 같은 테스트를 붙인 것입니다 — 이 문제는 구현체 하나가 잘한다고 풀리지 않습니다.

켤 만해지는 시점. parquet-java의 다음 릴리스가 나오고, arrow-rs #9619가 draft를 벗고 머지되고, Arrow C++가 thrift를 넘어 실제 로직을 붙이면 — 그때 NaN이 실제로 들어가는 컬럼부터 컬럼 단위로 켜는 게 맞습니다. 전면 전환이 아니라 컬럼 단위 옵트인이라는 설계 자체가 그렇게 쓰라는 뜻입니다.

그때까지의 안전한 기본값은 보수적으로 가는 것입니다. tustvold의 제안이 가장 명확합니다 — 구현체 상태가 이렇다면 float 프레디킷은 아예 푸시다운하지 않는 게 맞습니다. 느린 건 고칠 수 있지만 틀린 건 눈에 안 보입니다.

마치며

정리하면 이렇습니다. Parquet의 min/max 통계는 NaN이라는 순서 없는 값과 -0.0/+0.0이라는 같은 값의 두 비트 패턴 앞에서 계약이 성립하지 않았습니다. NaN을 통계에서 빼는 방편은 reader가 그 사실을 알 방법을 주지 않았고, 그 결과 있는 행을 못 찾는 오답이 나왔습니다. ColumnIndex는 아예 스펙 내부 모순에 걸려 있었습니다.

2.13.0의 해법은 두 조각의 결합입니다 — nan_count로 NaN의 존재를 명시하고, IEEE_754_TOTAL_ORDER로 비교를 결정론적으로 못박고, 새 순서를 쓰면 nan_count를 의무화해 "새 순서 = 신뢰할 수 있는 통계"라는 깨끗한 신호를 만든 것입니다. 3년 3개월과 두 번의 무산된 PR이 든 이유는, 두 안이 각각 반쪽이었고 그걸 인정하는 데 시간이 걸렸기 때문입니다.

이 글에서 가져갈 게 하나라면 이겁니다. 스펙이 릴리스됐다는 것과 문제가 해결됐다는 것은 다릅니다. 지금 이 순간 스펙은 완결됐고, 재현 가능한 오답은 여전히 열린 이슈이며, 어떤 메이저 구현체의 릴리스에도 수정이 들어 있지 않습니다. 포맷 스펙을 읽고 "고쳐졌다"고 결론 내리는 대신, 여러분이 실제로 쓰는 라이브러리의 버전에서 그게 동작하는지 확인하십시오. 이 경우 답은 아직 "아니오"입니다.

참고 자료

현재 단락 (1/107)

Parquet 파일이 빠른 이유의 큰 몫은 통계입니다. 로우 그룹마다, 컬럼 청크마다, 페이지마다 `min`, `max`, `null_count` 같은 요약을 적어 두고, 쿼리 엔...

작성 글자: 0원문 글자: 12,686작성 단락: 0/107