Skip to content

[branch-53] perf: skip ensure_distribution rebuild when children are unchanged#58

Merged
zhuqi-lucas merged 1 commit into
branch-53from
qizhu/enforce-dist-skip-rebuild-branch-53
May 29, 2026
Merged

[branch-53] perf: skip ensure_distribution rebuild when children are unchanged#58
zhuqi-lucas merged 1 commit into
branch-53from
qizhu/enforce-dist-skip-rebuild-branch-53

Conversation

@zhuqi-lucas
Copy link
Copy Markdown
Collaborator

Summary

Cherry-pick of upstream apache/datafusion#22521 (approved by 2010YOUY01 and alamb, awaiting maintainer merge) into our branch-53 fork. Companion to #57 (branch-52).

ensure_distribution was calling plan.with_new_children(children_plans) unconditionally after collecting the (possibly redistributed) children, even when none of the children were actually replaced. For nodes like ProjectionExec that path recomputes schema / equivalence properties / output ordering / partitioning via try_new — pure overhead when child Arcs are pointer-identical.

Routes the non-UnionExec branch through the existing with_new_children_if_necessary helper, which does the Arc::ptr_eq short-circuit and reuses the input plan when no children changed.

Why pick now

Linear X-2631. Profiling on NY5 prod showed ProjectionExec::with_new_children as the single largest cost inside ensure_distribution (1.94s of a 2.87s rule-time slice in a 60s CPU sample).

Adaptations from upstream

  • Upstream lives at datafusion/physical-optimizer/src/ensure_requirements/enforce_distribution.rs; branch-53 keeps the flat path. Same logic, different module path.
  • Upstream uses plan.is::<UnionExec>(); branch-53 still has plan.as_any().is::<UnionExec>(). Adjusted.

Affects

  • Staging: query servers will see the fast path after a DF rev bump (separate PR).
  • Production: same, after staging soak.

Tests

cargo test --release -p datafusion --test core_integration -- physical_optimizer::enforce_distribution — 63/63 pass (62 pre-existing + 1 new regression test ensure_distribution_reuses_plan_arc_when_no_redistribution_needed).

Micro-benchmark from upstream PR

Plan shape: 30-deep ProjectionExec stack over a sorted parquet scan, 5000 iterations.

  • Without fix: 852.74 ms total, 170.55 us/call
  • With fix: 296.81 ms total, 59.36 us/call
  • ~2.87x speedup, -65% CPU per call

…unchanged

Cherry-pick of upstream apache#22521 (approved by 2010YOUY01
and alamb, awaiting maintainer merge). Adapted to branch-53's file
layout (datafusion/physical-optimizer/src/enforce_distribution.rs vs
the upstream ensure_requirements/ subdirectory) and to the older
plan.as_any().is::<UnionExec>() API.

ensure_distribution was unconditionally calling plan.with_new_children
after collecting the (possibly redistributed) children, even when none
of the children were actually replaced. For nodes like ProjectionExec
that path runs through try_new and recomputes schema, equivalence
properties, output ordering, and partitioning, which is pure overhead
when the input Arcs are pointer-identical.

Routes the non-UnionExec branch through the existing
with_new_children_if_necessary helper, which does the Arc::ptr_eq
short-circuit and reuses the input plan when no children changed.
UnionExec to InterleaveExec special case still runs first because it
intentionally produces a new node even when child Arcs are unchanged.

Linear: X-2631
Copilot AI review requested due to automatic review settings May 28, 2026 08:26
Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

This PR cherry-picks upstream DataFusion change apache#22521 into branch-53 to reduce overhead in the EnforceDistribution optimizer rule by avoiding unnecessary plan rebuilds when child plans are unchanged.

Changes:

  • Update ensure_distribution to use with_new_children_if_necessary for non-UnionExec nodes, reusing the original Arc<dyn ExecutionPlan> when children are pointer-identical.
  • Add a regression test asserting ensure_distribution returns the exact same plan Arc when no redistribution is required (deep ProjectionExec chain, target_partitions = 1).

Reviewed changes

Copilot reviewed 2 out of 2 changed files in this pull request and generated no comments.

File Description
datafusion/physical-optimizer/src/enforce_distribution.rs Uses with_new_children_if_necessary to skip expensive with_new_children rebuilds when children are unchanged.
datafusion/core/tests/physical_optimizer/enforce_distribution.rs Adds regression coverage ensuring the optimizer reuses the input plan Arc when no redistribution occurs.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

@zhuqi-lucas zhuqi-lucas merged commit fa187fc into branch-53 May 29, 2026
59 checks passed
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.

3 participants