HIVE-29829: Iceberg: Partition-level column statistics refactor - #6707
Open
deniskuzZ wants to merge 5 commits into
Open
HIVE-29829: Iceberg: Partition-level column statistics refactor#6707deniskuzZ wants to merge 5 commits into
deniskuzZ wants to merge 5 commits into
Conversation
deniskuzZ
marked this pull request as draft
August 18, 2026 17:14
deniskuzZ
force-pushed
the
col_stats_refactor
branch
from
August 19, 2026 08:13
8c845b2 to
273ca7f
Compare
deniskuzZ
force-pushed
the
col_stats_refactor
branch
2 times, most recently
from
August 19, 2026 20:52
f73473a to
04270e5
Compare
deniskuzZ
force-pushed
the
col_stats_refactor
branch
from
August 20, 2026 15:09
04270e5 to
8efb3d0
Compare
deniskuzZ
force-pushed
the
col_stats_refactor
branch
from
August 21, 2026 00:11
8efb3d0 to
7fd415e
Compare
deniskuzZ
marked this pull request as ready for review
August 21, 2026 09:08
deniskuzZ
force-pushed
the
col_stats_refactor
branch
from
August 21, 2026 09:13
7fd415e to
0505fe2
Compare
Contributor
There was a problem hiding this comment.
Pull request overview
Refactors Hive/Iceberg column-statistics handling to better support partition-level semantics and snapshot/branch scenarios, including introducing a reader-materialized partition name virtual column.
Changes:
- Add
PARTITION__NAMEvirtual column and propagate it through vectorized and row-mode read paths for non-native partition support. - Rework column stats collection/persistence for non-native tables (Iceberg), including branch/snapshot-aware behavior and a new stats write policy.
- Update planner/optimizer and a large set of Iceberg query result baselines to reflect the new virtual column and revised stats behavior.
Reviewed changes
Copilot reviewed 92 out of 99 changed files in this pull request and generated 1 comment.
Show a summary per file
| File | Description |
|---|---|
| ql/src/java/org/apache/hadoop/hive/ql/stats/StatsUtils.java | Serve table-level col stats over pruned partitions for non-native tables; refine data-size derivation. |
| ql/src/java/org/apache/hadoop/hive/ql/stats/ColStatsProcessor.java | Adjust partition name derivation and storage-handler-based stats persistence behavior. |
| ql/src/java/org/apache/hadoop/hive/ql/stats/BasicStatsTask.java | Skip HMS partition handling for non-native partition support; adjust partition list retrieval. |
| ql/src/java/org/apache/hadoop/hive/ql/parse/ColumnStatsSemanticAnalyzer.java | Rewrite ANALYZE for non-native partition support using PARTITION__NAME grouping. |
| ql/src/java/org/apache/hadoop/hive/ql/parse/ColumnStatsAutoGatherContext.java | Disable partition-stats path for non-native partition support in auto-gather pipeline. |
| ql/src/java/org/apache/hadoop/hive/ql/optimizer/physical/Vectorizer.java | Switch vectorization virtual column from partition projection to partition name. |
| ql/src/java/org/apache/hadoop/hive/ql/optimizer/GenMapRedUtils.java | Preserve snapshot ref when constructing stats work from file sink context. |
| ql/src/java/org/apache/hadoop/hive/ql/metadata/VirtualColumn.java | Rename virtual column to PARTITION_NAME and update registry. |
| ql/src/java/org/apache/hadoop/hive/ql/metadata/Table.java | Adjust validity/virtual-column exposure for non-native partition support and meta tables. |
| ql/src/java/org/apache/hadoop/hive/ql/metadata/HiveStorageHandler.java | Remove unused partition transform specs API. |
| ql/src/java/org/apache/hadoop/hive/ql/metadata/Hive.java | Prevent HMS col-stats reads for non-native handler/branch snapshot scenarios. |
| ql/src/java/org/apache/hadoop/hive/ql/io/PositionDeleteInfo.java | Remove partition-projection from delete context payload. |
| ql/src/java/org/apache/hadoop/hive/ql/io/PartitionInfo.java | New IOContext payload for reader-materialized partition name. |
| ql/src/java/org/apache/hadoop/hive/ql/io/parquet/vector/VectorizedParquetRecordReader.java | Use row batch context column type infos when reading batches. |
| ql/src/java/org/apache/hadoop/hive/ql/io/IOContext.java | Track and parse PartitionInfo alongside other IO context info. |
| ql/src/java/org/apache/hadoop/hive/ql/io/HiveContextAwareRecordReader.java | Parse PartitionInfo on each next() for non-ACID readers. |
| ql/src/java/org/apache/hadoop/hive/ql/exec/StatsTask.java | Restore snapshot ref on table lookups for stats tasks. |
| ql/src/java/org/apache/hadoop/hive/ql/exec/MapOperator.java | Populate PARTITION__NAME virtual column from IOContext PartitionInfo. |
| ql/src/java/org/apache/hadoop/hive/ql/ddl/table/info/desc/DescTableOperation.java | Prefer table-level stats for non-native tables that don’t maintain partition stats. |
| iceberg/iceberg-handler/src/test/results/positive/vectorized_iceberg_read_parquet.q.out | Update expected plans/output for PARTITION__NAME virtual column. |
| iceberg/iceberg-handler/src/test/results/positive/vectorized_iceberg_read_orc.q.out | Update expected plans/output for PARTITION__NAME virtual column. |
| iceberg/iceberg-handler/src/test/results/positive/vectorized_iceberg_read_mixed.q.out | Update expected plans/output for PARTITION__NAME virtual column. |
| iceberg/iceberg-handler/src/test/results/positive/update_iceberg_partitioned_avro.q.out | Refresh expected plan warnings/order changes. |
| iceberg/iceberg-handler/src/test/results/positive/row_count.q.out | Update expected stats/plan output reflecting revised stats pipeline. |
| iceberg/iceberg-handler/src/test/results/positive/query_iceberg_metadata_of_partitioned_table.q.out | Adjust expected output for metadata queries after refactor. |
| iceberg/iceberg-handler/src/test/results/positive/mv_iceberg_orc8.q.out | Update expected plan output for removed/changed virtual column projection. |
| iceberg/iceberg-handler/src/test/results/positive/mv_iceberg_orc7.q.out | Update expected plan output for removed/changed virtual column projection. |
| iceberg/iceberg-handler/src/test/results/positive/mv_iceberg_orc5.q.out | Update expected plan output for removed/changed virtual column projection. |
| iceberg/iceberg-handler/src/test/results/positive/mv_iceberg_orc4.q.out | Update expected plan output for removed/changed virtual column projection. |
| iceberg/iceberg-handler/src/test/results/positive/metadata_delete.q.out | Update expected plan output after virtual column changes. |
| iceberg/iceberg-handler/src/test/results/positive/merge_iceberg_orc.q.out | Update expected plan output after virtual column changes. |
| iceberg/iceberg-handler/src/test/results/positive/llap/vectorized_iceberg_read_parquet.q.out | Update expected LLAP vectorization schema for PARTITION__NAME. |
| iceberg/iceberg-handler/src/test/results/positive/llap/vectorized_iceberg_read_orc.q.out | Update expected LLAP vectorization schema for PARTITION__NAME. |
| iceberg/iceberg-handler/src/test/results/positive/llap/vectorized_iceberg_read_mixed.q.out | Update expected LLAP vectorization schema for PARTITION__NAME. |
| iceberg/iceberg-handler/src/test/results/positive/llap/llap_iceberg_read_orc.q.out | Refresh expected LLAP plan/stats output after stats changes. |
| iceberg/iceberg-handler/src/test/results/positive/llap/iceberg_minor_compaction_unpartitioned.q.out | Update expected COLUMN_STATS_ACCURATE output after stats persistence change. |
| iceberg/iceberg-handler/src/test/results/positive/llap/iceberg_minor_compaction_partition_evolution.q.out | Update expected COLUMN_STATS_ACCURATE output after stats persistence change. |
| iceberg/iceberg-handler/src/test/results/positive/llap/iceberg_minor_compaction_bucket.q.out | Update expected COLUMN_STATS_ACCURATE output after stats persistence change. |
| iceberg/iceberg-handler/src/test/results/positive/llap/iceberg_major_compaction_single_partition_with_evolution2.q.out | Update expected COLUMN_STATS_ACCURATE output after stats persistence change. |
| iceberg/iceberg-handler/src/test/results/positive/llap/iceberg_major_compaction_partition_evolution2.q.out | Update expected COLUMN_STATS_ACCURATE output after stats persistence change. |
| iceberg/iceberg-handler/src/test/results/positive/llap/iceberg_major_compaction_partition_evolution.q.out | Refresh expected plan/stats output after compaction/stats refactor. |
| iceberg/iceberg-handler/src/test/results/positive/llap/iceberg_major_compaction_partition_evolution_ordered.q.out | Update expected COLUMN_STATS_ACCURATE output after stats persistence change. |
| iceberg/iceberg-handler/src/test/results/positive/llap/iceberg_create_locally_zordered_table.q.out | Update expected plan edges/aggregations after stats pipeline changes. |
| iceberg/iceberg-handler/src/test/results/positive/llap/iceberg_bucket_map_join_8.q.out | Update expected plan/stats output after stats changes. |
| iceberg/iceberg-handler/src/test/results/positive/llap/iceberg_bucket_map_join_6.q.out | Update expected plan/stats output after stats changes. |
| iceberg/iceberg-handler/src/test/results/positive/llap/iceberg_bucket_map_join_5.q.out | Update expected plan/stats output after stats changes. |
| iceberg/iceberg-handler/src/test/results/positive/llap/iceberg_bucket_map_join_4.q.out | Update expected plan/stats output after stats changes. |
| iceberg/iceberg-handler/src/test/results/positive/llap/iceberg_bucket_map_join_3.q.out | Update expected plan/stats output after stats changes. |
| iceberg/iceberg-handler/src/test/results/positive/llap/iceberg_bucket_map_join_2.q.out | Update expected plan/stats output after stats changes. |
| iceberg/iceberg-handler/src/test/results/positive/llap/hadoop_catalog_create_table.q.out | Update expected COLUMN_STATS_ACCURATE output after stats persistence change. |
| iceberg/iceberg-handler/src/test/results/positive/iceberg_truncate_partition_with_evolution.q.out | Update expected stats/plan output after virtual column/stats refactor. |
| iceberg/iceberg-handler/src/test/results/positive/iceberg_stats_with_ppr.q.out | Update expected column stats state after refactor. |
| iceberg/iceberg-handler/src/test/results/positive/iceberg_pcr_null_partition.q.out | Update expected column stats state after refactor. |
| iceberg/iceberg-handler/src/test/results/positive/iceberg_merge_schema.q.out | Update expected vectorization schema output for PARTITION__NAME. |
| iceberg/iceberg-handler/src/test/results/positive/iceberg_load_data.q.out | Update expected plan edges/shuffles after stats changes. |
| iceberg/iceberg-handler/src/test/results/positive/iceberg_insert_into_partition_with_evolution.q.out | Update expected plan edges/output after stats changes. |
| iceberg/iceberg-handler/src/test/results/positive/iceberg_explain_formatted.q.out | Update expected formatted explain JSON for PARTITION__NAME. |
| iceberg/iceberg-handler/src/test/results/positive/dynamic_semijoin_reduction.q.out | Update expected plan/stats output after stats changes. |
| iceberg/iceberg-handler/src/test/results/positive/delete_iceberg_mixed.q.out | Update expected plan/stats output after delete path changes. |
| iceberg/iceberg-handler/src/test/results/positive/ctas_iceberg_partitioned_orc.q.out | Update expected COLUMN_STATS_ACCURATE output after stats persistence change. |
| iceberg/iceberg-handler/src/test/results/positive/col_stats.q.out | Update expected COLUMN_STATS_ACCURATE per-column map after refactor. |
| iceberg/iceberg-handler/src/test/results/positive/bucket_map_join_9.q.out | Update expected plan/stats output after stats changes. |
| iceberg/iceberg-handler/src/test/java/org/apache/iceberg/mr/hive/writer/TestHiveIcebergDeleteWriter.java | Update delete-record schema creation for new delete serde schema signature. |
| iceberg/iceberg-handler/src/test/java/org/apache/iceberg/mr/hive/vector/TestHiveIcebergVectorization.java | Pass FileScanTask into batch iterator to support task-scoped virtuals. |
| iceberg/iceberg-handler/src/test/java/org/apache/iceberg/mr/hive/TestHiveIcebergSelects.java | Add test ensuring PARTITION__NAME predicates are not pushed down to Iceberg. |
| iceberg/iceberg-handler/src/main/java/org/apache/iceberg/mr/mapreduce/IcebergRecordReader.java | Make virtual column iterator task-aware and simplify constants map logic. |
| iceberg/iceberg-handler/src/main/java/org/apache/iceberg/mr/mapreduce/IcebergMergeRecordReader.java | Use merge-task delete schema and pass spec/partition info for virtuals. |
| iceberg/iceberg-handler/src/main/java/org/apache/iceberg/mr/mapreduce/AbstractIcebergRecordReader.java | Update virtual-column schema construction to new helper signature. |
| iceberg/iceberg-handler/src/main/java/org/apache/iceberg/mr/hive/writer/HiveIcebergDeleteWriter.java | Use merge-aware position delete extraction. |
| iceberg/iceberg-handler/src/main/java/org/apache/iceberg/mr/hive/writer/HiveIcebergCopyOnWriteRecordWriter.java | Use updated position delete extraction signature. |
| iceberg/iceberg-handler/src/main/java/org/apache/iceberg/mr/hive/vector/HiveVectorizedReader.java | Thread FileScanTask through batch iterator creation. |
| iceberg/iceberg-handler/src/main/java/org/apache/iceberg/mr/hive/vector/HiveDeleteFilter.java | Use diamond operator for CloseableIterable implementation. |
| iceberg/iceberg-handler/src/main/java/org/apache/iceberg/mr/hive/vector/HiveBatchIterator.java | Populate virtual columns from FileScanTask, including PARTITION__NAME. |
| iceberg/iceberg-handler/src/main/java/org/apache/iceberg/mr/hive/stats/ColStatsWritePolicy.java | New policy enum to decide replace/merge/skip for stats file writes. |
| iceberg/iceberg-handler/src/main/java/org/apache/iceberg/mr/hive/IcebergAcidUtil.java | Rework virtual column plumbing and delete serde schemas; add PartitionInfo propagation. |
| iceberg/iceberg-handler/src/main/java/org/apache/iceberg/mr/hive/HiveIcebergSerDe.java | Update projected schema logic and merge-task delete schema selection. |
| iceberg/iceberg-handler/src/main/java/org/apache/iceberg/mr/hive/compaction/IcebergCompactionService.java | Disable follow-up compute stats for compaction since stats are gathered in-query. |
| iceberg/iceberg-catalog/src/main/java/org/apache/iceberg/hive/MetastoreUtil.java | Simplify partition key derivation (currently still disabled via TODO). |
Suppressed comments (1)
iceberg/iceberg-handler/src/main/java/org/apache/iceberg/mr/hive/vector/HiveBatchIterator.java:136
BytesColumnVector.filldoes not resetnoNulls, andString#getBytes()is platform-default charset. SincePARTITION_NAMEis always set for Iceberg tasks (usesDummyPartition.VOIDfor unpartitioned), setnoNulls=trueand encode with UTF-8 for deterministic behavior and less null-handling overhead.
case PARTITION_NAME:
bcv = (BytesColumnVector) batch.cols[idx];
bcv.fill(partitionName.getBytes());
break;
💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
Comment on lines
121
to
124
| case FILE_PATH: | ||
| value = idToConstant.get(MetadataColumns.FILE_PATH.fieldId()); | ||
| BytesColumnVector bcv = (BytesColumnVector) batch.cols[idx]; | ||
| if (value == null) { | ||
| bcv.noNulls = false; | ||
| bcv.isNull[0] = true; | ||
| bcv.isRepeating = true; | ||
| } else { | ||
| bcv.fill(((String) value).getBytes()); | ||
| } | ||
| bcv.fill(filePath.getBytes()); | ||
| break; |
…berg virtual column plumbing Adds VirtualColumn.PARTITION_NAME, materialized by the Iceberg readers: vectorized via HiveBatchIterator, row mode via PartitionInfo -> IOContext -> MapOperator. Refactors the read path to take everything the file already carries from the scan task instead of the per-record constants map: spec id, partition hash, file path, partition name, first row id and file sequence number are computed once per task in both VirtualColumnAwareIterator and HiveBatchIterator. Drops the now unread _partition column from the ACID read schema, along with the write-only VIRTUAL_COLS_TO_META_COLS map and the per-record helpers it fed. Fixes VectorizedParquetRecordReader taking a column type from the job column list while indexing it with a batch column number: the two orders diverge past the data columns because the batch drops virtual columns the readers cannot fill.
…ead of a virtual column The partition key a merge task carries is read back only by HiveIcebergDeleteWriter under isMergeTask: an ordinary delete derives the key from the row data, and a merge task cannot because it reads delete files, whose records hold only a path and a position. Declaring it as a virtual column put an always empty string into every DELETE, UPDATE and MERGE record and into every Iceberg plan. It now lives in a merge specific serde layout that IcebergMergeRecordReader and HiveIcebergSerDe select on the merge task flag, so the ordinary delete record is one column shorter and the plans no longer estimate it.
…tatistics Adds hive.iceberg.stats.collect.partlevel (default false), scoping column statistics granularity for Iceberg tables independently of the generic hive.analyze.stmt.collect.partlevel.stats. Partition-level statistics are produced by ANALYZE; every other write maintains table-level ones. Keys the column-statistics read path on the calling API rather than on session config, so a granularity mismatch cannot surface a wrongly-shaped blob. Stores branch-scoped statistics on the branch's snapshot and stops branch writes from overwriting the table-scoped metastore row, including the footer scan path used by ANALYZE ... COMPUTE STATISTICS. Lets a whole-table INSERT OVERWRITE of a partitioned table replace its column statistics, which previously skipped because whole-table and partition-scoped overwrites are indistinguishable in the snapshot summary.
Derive partition names through the Iceberg spec so a write keys statistics the way a read looks them up; substitute per partition for a scoped write or ANALYZE; gather partition-level statistics for CTAS.
deniskuzZ
force-pushed
the
col_stats_refactor
branch
from
August 22, 2026 17:22
49ad50c to
2419328
Compare
|
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.



What changes were proposed in this pull request?
Why are the changes needed?
Does this PR introduce any user-facing change?
How was this patch tested?