weijietong opened a new pull request, #10836:
URL: https://github.com/apache/paimon/pull/10836

   ### Purpose
   This PR introduces a customized Parquet footer parser to significantly 
improve metadata reading performance, especially for wide tables with hundreds 
to thousands of columns.
   
     #### Background
   
     When reading Parquet files, Paimon needs to parse the footer metadata 
serialized with Thrift Compact Protocol. For wide tables (hundreds to thousands 
of columns), footer parsing becomes a significant performance bottleneck. The 
official ParquetMetadataConverter materializes every column chunk's metadata 
including all Statistics, even when only a subset of
     columns is needed.
   
     #### Implementation
   
     The selective footer parser walks the Thrift compact-protocol bytes 
directly with a hand-written ThriftCompactReader and:
   
     - Selective materialization: Only materializes column chunks whose 
top-level column is requested. Other column chunks are still scanned (the 
compact protocol forces a full byte pass) but their bytes are not retained.
     - Statistics skipping: Optionally skips Statistics parsing for kept 
columns (AI training reads never consume footer statistics since stats-based 
row-group filtering requires a pushdown filter).
     - Schema preservation: Always materializes the complete schema (including 
full LogicalType union) regardless of the column subset.
     - Fallback mechanism: Automatically falls back to the official parser when 
encountering encrypted footers, encrypted columns, or unexpected structures.
   
     Object construction is delegated to 
ParquetMetadataConverter.fromParquetMetadata() to reuse the battle-tested 
conversion, ensuring byte-for-byte equivalence with the official reader for the 
retained subset.
   
     #### Performance Results
   
     Benchmark on a 232MB file with 1,570 columns and 8 row groups (1.29MB 
footer):
   
     | Requested Columns | Official Parser | Selective Parser | Speedup | 
Memory Saved |
   | ----------------- | --------------- | ---------------- | ------- | 
------------ |
   | 10 (0.6%)         | 21.11 ms        | 2.46 ms          | 8.6x    | 54%     
     |
   | 50 (3.2%)         | 21.65 ms        | 2.62 ms          | 8.3x    | 53%     
     |
   | 100 (6.4%)        | 21.06 ms        | 2.90 ms          | 7.3x    | 52%     
     |
   | 500 (31.8%)       | 21.58 ms        | 4.50 ms          | 4.8x    | 42%     
     |
   | 1000 (63.7%)      | 20.62 ms        | 6.26 ms          | 3.3x    | 29%     
     |
   | 1570 (100%)       | 20.21 ms        | 8.47 ms          | 2.4x    | 14%     
     |
   
     Even in full-parse mode (all columns requested), the selective parser 
achieves 2.4x speedup due to:
     - Hand-written parser vs Thrift-generated code (avoiding reflection and 
setter overhead)
     - Direct byte array access vs unbuffered TIOStreamTransport (avoiding 
50,000+ byte[] allocations for Statistics)
     - No String.intern() calls (avoiding global String pool synchronization)
     - Single-phase parsing (avoiding Thrift tree memory)
     - Avoiding ~8 wrapper objects per column chunk
   
     #### Integration
   
     The selective parser is enabled in ParquetReaderFactory when no pushdown 
predicates are present (since predicates require Statistics for row-group 
filtering). It's controlled by two configuration properties:
     - paimon.parquet.footer.requested.columns: Comma-separated list of 
top-level column names to retain
     - paimon.parquet.footer.skip.statistics: Whether to skip Statistics 
parsing (default: true for AI training workloads)
   
   ### Tests
   
     Added comprehensive test coverage in SelectiveFooterParserTest with 30 
test cases:
   
     Equivalence Tests
     - Full parse equivalence with official NO_FILTER parse
     - Selective subset parse correctness
     - Dropped columns do not affect block-level info
     - Skip statistics parse mode
   
     Complex Schema Tests
     - Deep nesting (3+ levels)
     - Map type (key-value structures)
     - Array type (list structures)
   
     Boundary Condition Tests
     - Empty file (0 rows)
     - Single row group
     - All columns requested
     - Non-existent columns requested
   
     Exception Path Tests
     - Malformed footer (truncated)
     - Malformed footer (wrong thrift type)
     - Fallback signal handling
   
     Encryption Tests
     - Encrypted footer fallback verification
     - Encrypted column fallback verification
   
     Integration Tests
     - ParquetReadOptions integration
     - Split requested columns utility
     - Many row groups (1000 rows, small row group size)
     - Selective parse with nested columns
   
     All 30 tests pass successfully, validating byte-for-byte equivalence with 
the official parser for the retained subset.


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: [email protected]

For queries about this service, please contact Infrastructure at:
[email protected]

Reply via email to