Skip to content

HIVE-29834: Iceberg: Answer MIN, MAX and COUNT from the handler's column statistic - #6716

Open
deniskuzZ wants to merge 2 commits into
apache:masterfrom
deniskuzZ:col_stats_stats_opt
Open

HIVE-29834: Iceberg: Answer MIN, MAX and COUNT from the handler's column statistic#6716
deniskuzZ wants to merge 2 commits into
apache:masterfrom
deniskuzZ:col_stats_stats_opt

Conversation

@deniskuzZ

@deniskuzZ deniskuzZ commented Aug 21, 2026

Copy link
Copy Markdown
Member

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?

depends on #6707

@deniskuzZ deniskuzZ changed the title [WIP] HIVE-29834: Iceberg: Answer an aggregate from a handler's column statistics [WIP] HIVE-29834: Iceberg: Answer MIN, MAX and COUNT from the handler's column statistic Aug 28, 2026
@deniskuzZ
deniskuzZ force-pushed the col_stats_stats_opt branch from 4fadd60 to 876c853 Compare August 28, 2026 13:10
@deniskuzZ
deniskuzZ force-pushed the col_stats_stats_opt branch from 876c853 to a7fa8b2 Compare August 28, 2026 23:55
@deniskuzZ
deniskuzZ force-pushed the col_stats_stats_opt branch from a7fa8b2 to 4173058 Compare August 29, 2026 04:39
@deniskuzZ
deniskuzZ force-pushed the col_stats_stats_opt branch from 4173058 to 27b2198 Compare August 29, 2026 11:03
@deniskuzZ
deniskuzZ force-pushed the col_stats_stats_opt branch from 27b2198 to fc3051a Compare August 29, 2026 11:13
@deniskuzZ
deniskuzZ force-pushed the col_stats_stats_opt branch from fc3051a to 9fb4799 Compare August 29, 2026 14:48
…ne them on read

A partitioned table already kept its column statistics one entry per partition,
but every gather held them all in memory, wrote each entry as a serialized Java
object, and every read fetched one blob per partition and decoded all of it.
None of that survives a table of any size.

A gather is now pulled through the writer a batch at a time, so a table of two
thousand partitions is never held at once, and an entry is written as the Thrift
struct it is. A blob holds one partition, every column's entry behind the field
it is for and its own length, so a scan decodes the columns it asked about and
steps over the rest. The blobs a scan wants are read in as few requests as their
places allow, merging what lies between them where crossing it costs less than
the seek it saves - which the store says, not this.

Every entry keeps the bit vector its distinct count is merged from. A count per
partition is only worth having if the counts can be merged across the partitions
a scan reads, and only a vector merges them: without one the fold falls back to
the largest single partition's count, which for the partition column of an
identity-partitioned table is one however many partitions are read.

What still describes the data is decided from the snapshot a file was written
for, so statistics separated from their rows are not served as though they
stood. ANALYZE stores what it read, an overwrite what it replaced, and a major
compaction of one current-spec partition refreshes it; a plain INSERT maintains
none, and its partitions read as stale until recomputed. A branch's statistics
stay on the branch, a file states every column it comes to hold so that whether
a column has any is answerable from the table's metadata without opening it, and
a file describing nothing is never committed in place of one that describes
something.

Where no stored statistics answer, the bounds the manifests already hold do, and
they are folded a file at a time: a file states its metrics once for all of its
columns, so what holds them is read where the file is in hand rather than again
by each column of it. Where a column is one the spec partitions by identity, the
partition is the value, so its bounds are exact and are stated even by a file
that recorded no metrics of its own - which Iceberg stops inferring past its
hundredth column.
…umn statistics

MIN, MAX and COUNT over a column are facts the stored statistics already state,
so a query asking only for them is answered from what a storage handler holds
rather than by reading the rows. The statistics of every aggregate in a query
are fetched at once, and a partitioned table is answered only from statistics
that describe the partitions, the columns and the snapshot the scan asks about
- a partition whose statistics do not cover every asked column, or which a live
delete of no named partition may have changed, is not answered for.

A table's size comes from its storage handler rather than from listing what its
location holds, and whether a join can be a sort-merge is decided before its
big table is elected, so an election made on the handler's numbers is not
undone by one made on the listing's.
@sonarqubecloud

Copy link
Copy Markdown

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants