Skip to content

fix(scheduler): prune scan files by statistics and balance file groups - #2558

Merged
andygrove merged 4 commits into
apache:mainfrom
andygrove:andygrove/issue-2551-draft-pr
Oct 8, 2026
Merged

andygrove merged 4 commits into
apache:mainfrom
andygrove:andygrove/issue-2551-draft-pr

Conversation

@andygrove

@andygrove andygrove commented Oct 7, 2026 •

Copy link
Copy Markdown
Member

Which issue does this PR close?

Closes #2551.

Rationale for this change

DataFusion builds a file scan's file groups before any predicate is applied: files are sorted by path and cut into contiguous runs. Pruning from Parquet statistics only happens later, inside each task. When the files are clustered by the filtered column (for example Hive-style date directories filtered by a date range), every file that survives pruning sits in a few neighbouring groups. Only the tasks that own those groups have rows to read, the other tasks open their files and skip them, and the stage takes as long as the busiest few tasks.

What changes are included in this PR?

  • New BalanceAndPruneFileGroups physical optimizer rule (ballista/scheduler/src/physical_optimizer/file_group_balance.rs). It evaluates the scan's predicate against the file statistics collected during planning, drops files that cannot match, and deals the remaining files round-robin over the scan's file groups.
  • The rule leaves a scan untouched when it declares an output partitioning or ordering, must preserve file order, has a single group, has no useful predicate, or when nothing can be pruned. Files without statistics are always kept. The group count never grows, and shrinks only when fewer files survive than there were groups.
  • It is applied in the static planner right after the physical plan is created, and in AQE plan preparation right after FilterPushdown (so the predicate is on the scan and DataFusion's file scan repartitioning sees the pruned files). Physical plans submitted directly by a client are not rewritten.
  • New setting ballista.optimizer.balance_scan_file_groups (default true) to turn it off, with the generated configs.md updated.

Tests: unit tests for the rule, including a case that plans a real ListingTable over Parquet files clustered by the filtered column.

Are there any user-facing changes?

A new config option, ballista.optimizer.balance_scan_file_groups. Scans with selective predicates on clustered columns may now plan fewer, better balanced file groups. No public API changes.

DataFusion builds a file scan's file groups before any predicate is
applied, so a selective filter on a column the files are clustered by
leaves a few groups with all the surviving files and the rest empty.

Add the BalanceFileGroups rule, which prunes files using the statistics
collected during planning and deals the survivors round-robin over the
scan's groups. It runs after planning in the static planner and during
plan preparation in AQE, and is controlled by
ballista.optimizer.balance_scan_file_groups.
@github-actions github-actions Bot added the documentation Improvements or additions to documentation label Oct 7, 2026
@andygrove
andygrove marked this pull request as ready for review October 7, 2026 06:54
A single file with missing or inexact statistics made the batched
pruning call return nothing for the column, so no file was pruned at
all. Evaluate each file on its own and keep any file that cannot be
judged.
The rule now reads ballista.optimizer.balance_scan_file_groups from the
ConfigOptions it is given, so neither planner gates it. Also avoid
cloning files that are about to be discarded and tidy the tests.

@milenkovicm milenkovicm left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM, thanks @andygrove

@villebro villebro left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks great! As a long term fix, should we consider moving the pruning/rebalancing logic to DataFusion? It seems DF could benefit from this optimization independently of Ballista.

/// Files without statistics are always kept. The number of file groups never
/// grows, and shrinks only when fewer files survive than there were groups.
#[derive(Debug, Default)]
pub struct BalanceFileGroups;

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: As pruning is a big part of this, should this be called BalanceAndPruneFileGroups?

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good call, renamed it to BalanceAndPruneFileGroups in 168b80b.

@andygrove

Copy link
Copy Markdown
Member Author

Thanks @villebro, good call. I filed apache/datafusion#26130 to prune files by statistics in ListingTable before it builds the file groups.

DataFusion mostly hides this skew in a single process because idle partitions steal files from their siblings. We can't rely on that in Ballista since each partition runs as its own task. If the upstream change lands, DataFusion's existing file splitting would spread the remaining files and we could drop this rule. Until then this rule covers it on our side.

…roups

The rule prunes scan files by statistics as well as rebalancing them, so
name it after both, as suggested in review.
@villebro

villebro commented Oct 8, 2026

Copy link
Copy Markdown
Member

DataFusion mostly hides this skew in a single process because idle partitions steal files from their siblings. We can't rely on that in Ballista since each partition runs as its own task. If the upstream change lands, DataFusion's existing file splitting would spread the remaining files and we could drop this rule. Until then this rule covers it on our side.

Oh interesting, I wasn't aware of this file stealing detail. TIL 👍

@andygrove
andygrove merged commit cf2642f into apache:main Oct 8, 2026
25 of 26 checks passed
@avantgardnerio

Copy link
Copy Markdown
Contributor

FWIW, with MPTs, we get whatever functionality they add for free.

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

Labels

documentation Improvements or additions to documentation

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Scan tasks are skewed when Parquet statistics prune most files: file groups are built before pruning

4 participants