-
Notifications
You must be signed in to change notification settings - Fork 91
feat(datafusion): support ANALYZE TABLE on catalog-managed format tables - #815
Draft
sundapeng wants to merge 7 commits into
Draft
feat(datafusion): support ANALYZE TABLE on catalog-managed format tables #815sundapeng wants to merge 7 commits into
sundapeng wants to merge 7 commits into
Conversation
sundapeng
force-pushed
the
feat/format-table-analyze
branch
4 times, most recently
from
September 11, 2026 15:40
9ea2505 to
985e5a9
Compare
...d format tables A Format Table whose partitions a REST catalog manages is read from its registrations, but DataFusion could not change them. This adds the statements that do: - SHOW PARTITIONS [PARTITION (...)] lists the registrations in escaped key=value form, read with the column types and optionally filtered by any subset of partition values. - ALTER TABLE ... ADD [IF NOT EXISTS] PARTITION (...) registers complete specs, then creates their directories. - ALTER TABLE ... DROP [IF EXISTS] PARTITION (...) takes several specifications, expands a partial one to every registered partition it matches and compares values as the catalog holds them, so `month = 1` does not select `month=01`, as Java resolveFormatTablePartitionsForDrop does. Complete specifications are looked up by name; a partial one reads the registry once. Registrations go first and directories after; a partition at a custom location is only unregistered. Partition literals are read with the column type through the parser that reads registrations and directories, the way Java casts partition strings, so a BOOLEAN value accepts t/true/y/yes/1 and their false counterparts. Catalog gains drop_partitions. RESTCatalog refuses it for a table without catalog-managed partitions, since the endpoint only removes metadata and would leave the data of any other table in place while reporting success.
...bles Describe catalog-managed Format Table partitions in the SQL guide: the metastore.partitioned-table prerequisite, SHOW / ADD / DROP PARTITION, how partition values are read, what each statement does to registrations and directories, and how a partition at a custom location is treated.
This was referenced Sep 11, 2026
sundapeng
force-pushed
the
feat/format-table-analyze
branch
from
September 11, 2026 17:38
985e5a9 to
c2a25f2
Compare
... PARTITION A blank string for a string partition column is formatted as the default partition name, so DROP PARTITION (dt = '') unregistered the NULL partition and deleted its directory, and ADD PARTITION (dt = '') registered it. Refuse an empty or whitespace-only string for a string partition column in ADD and DROP PARTITION, as Java PaimonFormatTable.requireNameablePartitionValues does. SHOW PARTITIONS still accepts it as a filter.
...bles
A catalog-managed Format Table reads only the partitions its catalog
registers, so a partition directory written without a registration stays
invisible, and a registration whose directory is gone points at nothing.
MSCK REPAIR TABLE [{ADD|DROP|SYNC} PARTITIONS] reconciles the two:
- ADD, the default, registers every discovered partition the catalog does
not hold; DROP unregisters every registration without a directory; SYNC
does both. Nothing on storage is created or deleted.
- Directory discovery and the catalog listing both finish before any
change, and DROP and SYNC fail on a table directory that cannot be
listed rather than reading it as empty.
- Partitions are matched by escaped name and registered with the values
as their directories spell them, so month=01 stays month=01.
- A partition registered at a custom location is never unregistered,
since its data does not live under the table directory.
FormatTablePartitionPaths gains discover, which skips hidden directories
and segments outside the configured layout, and fails on a matching
segment that is not canonically escaped. unescape_path_name moves from
the scan to spec::partition_utils, beside escape_path_name, so discovery
and the scan share it.
Describe the ADD, DROP and SYNC modes, that repair only changes registrations, that discovery and the catalog listing finish before any change, and that a partition at a custom location is never unregistered.
Split out of apache#591. A Format Table whose partitions the REST catalog manages had no way to report what those partitions hold. ANALYZE TABLE t [PARTITION (...)] COMPUTE STATISTICS [NOSCAN] measures the registered partitions from storage and reports the result through create_partitions_with_statistics with replaceStatistics, as Java PaimonAnalyzeFormatTablePartitionsCommand does: - NOSCAN stops at the listing: file count, byte size and the latest file modification time. A full ANALYZE also reads Parquet and ORC footers for row counts; a footer that cannot be read leaves the partition's row count unknown rather than short, and an empty partition holds exactly zero rows. - PARTITION (...) selects a leading run of partition values. A prefix with no registered partition, a partition at a custom location, FOR COLUMNS and CACHE METADATA are refused, as is a table whose partitions the catalog does not manage. - format-table.statistics.parallelism (default 8) bounds the listings and footer reads in flight. The collector lists each partition through the same helper the scan now uses, so a measurement counts exactly the files a scan of that partition reads and leaves committer staging trees out. Its streams own their items so that the future of every SQLContext statement stays Send.
Describe what NOSCAN and a full ANALYZE measure, how PARTITION selects partitions, what is refused, and format-table.statistics.parallelism.
sundapeng
force-pushed
the
feat/format-table-analyze
branch
from
September 12, 2026 06:45
c2a25f2 to
4f83b41
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.
Uh oh!
There was an error while loading. Please reload this page.
Purpose
Child of #591, which stays open as a draft that shows the full feature. A Format Table loaded from a REST catalog with
metastore.partitioned-table=truehas its partitions registered in the catalog, and the catalog can hold statistics for each of them: record count, file count, size and last file creation time. The Rust client had no way to measure a partition and report them. This addsANALYZE TABLEfor such tables, following the JavaPaimonAnalyzeFormatTablePartitionsCommandandFormatTablePartitionStatsCollector.Depends on #817 , which depends on #816. Until they merge, this branch includes their five commits; please review only the last two:
feat(datafusion): support ANALYZE TABLE on catalog-managed format tablesanddocs(datafusion): document ANALYZE TABLE for format tables.This PR was rebased onto the restructured stack. ANALYZE itself is unchanged: its tests now use the shared helpers of #816, and a value in
PARTITION (...)is read by the sharedparse_format_partition_valuethat #816 introduces for partition literals.Brief change log
ANALYZE TABLE t [PARTITION (...)] COMPUTE STATISTICS [NOSCAN]on a Format Table with catalog-managed partitions measures the registered partitions from storage and reports them throughCatalog::create_partitions_with_statisticswithreplaceStatistics=true, so each measured field replaces what the catalog holds. It never adds or removes a partition.NOSCANreports the file count, total size and latest file modification time, and leaves the row count unknown (-1).PARTITION (...)selects a leading run of partition values; a column named without a value means every value of it. A prefix with no registered partition is an error.FOR COLUMNS,CACHE METADATA, a missingCOMPUTE STATISTICS, tables whose partitions the catalog does not manage, an empty or whitespace-only string inPARTITION (...)for a string column (it would name the default partition, as ADD and DROP in feat(datafusion): add SHOW, ADD and DROP PARTITION for catalog-managed format tables #816 refuse), and any selected partition at a custom location.format-table.statistics.parallelism(a session setting,SET 'paimon.<key>', as in Java; default 8, at least 1) bounds the listings and footer reads in flight.FormatTablePartitionStatsCollector, public inpaimon::table, does the measuring. A listing failure fails the whole collection, since a truncated listing cannot be told apart from a partition that lost files.list_format_table_data_files, which the collector shares, so a measurement counts exactly the files a scan of that partition reads and leaves committer staging trees out (the rule from fix(table): skip staging files and list format table partitions concurrently #813 ). The scan's behaviour is unchanged.read_file_row_countreads the row count of a Parquet or ORC file from its footer without decoding rows.Follow-up: using the reported row counts in DataFusion scan statistics, as apache/paimon#9351 does for Spark.
Tests
crates/integrations/datafusion/tests/rest_format_partition_sql.rs:PARTITIONselecting a leading run of values, and its errors;FOR COLUMNS, a blank string partition value, a partition at a custom location, a non-positive parallelism read as one, and a table without catalog-managed partitions.format_table_scan::tests::test_data_file_listing_returns_what_a_partition_scan_readsfor the shared listing.SQLContext::sqlstaysSendnow covers the new statement too.Commands run on the top commit:
fmt and clippy pass.
paimon: 2967 tests pass.paimon-rest-server: 10 tests pass.paimon-datafusion: 780 pass, including the 15 tests inrest_format_partition_sql.rs, and 39 fail. The failures are the 39 tests that also fail by name onmainin this environment, because they read fixture tables provisioned bymake docker-up(two also need the lumina native library).Additions without a direct Java counterpart
read_file_row_countreads a Parquet or ORC file's row count from its footer. Java counts rows with the format'sSimpleStatsExtractor, which the Rust client does not have for Format Tables.ANALYZEmeasures in process with bounded concurrency, where Spark spreads the footer reads over executors (PaimonAnalyzeFormatTablePartitionsCommand.measureOnExecutors).API and Format
paimon::table::FormatTablePartitionStatsCollector.format-table.statistics.parallelism, read bySQLContext.The storage format is unchanged.
Documentation
docs/src/sql.mdgains anANALYZE TABLEsubsection under Format Table Partitions and listsANALYZE TABLEin the SQL support scope.