Skip to content

[SPARK-58138][SQL] Preserve child output partitioning through BIN BY#57275

Closed
vranes wants to merge 1 commit into
apache:masterfrom
vranes:bin-by-output-partitioning
Closed

[SPARK-58138][SQL] Preserve child output partitioning through BIN BY#57275
vranes wants to merge 1 commit into
apache:masterfrom
vranes:bin-by-output-partitioning

Conversation

@vranes

@vranes vranes commented Jul 15, 2026

Copy link
Copy Markdown
Contributor

What changes were proposed in this pull request?

This PR makes BinByExec extend PartitioningPreservingUnaryExecNode so it reports an outputPartitioning derived from its child.

A child partitioning is kept only when its keys are in the operator's output: a partitioning on a pass-through column survives, while one on a scaled DISTRIBUTE column is dropped (that column has a fresh ExprId absent from the output). Keeping the pass-through case is safe because BIN BY transforms each partition independently and pass-through columns hold the same value across an input row's sub-rows.

Why are the changes needed?

A downstream operator clustered on a pass-through column that the child already partitions on would otherwise get an unnecessary shuffle.

Does this PR introduce any user-facing change?

No. BIN BY is gated off by default (spark.sql.binByRelationOperator.enabled).

How was this patch tested?

ProjectedOrderingAndPartitioningSuite: a pass-through key is preserved as HashPartitioning, a scaled DISTRIBUTE key is dropped to UnknownPartitioning, and a mixed key is dropped whole.

Was this patch authored or co-authored using generative AI tooling?

Generated-by: Claude Code (Anthropic)

@vranes
vranes force-pushed the bin-by-output-partitioning branch from e2844ca to 0e93786 Compare July 15, 2026 12:39
@vranes
vranes marked this pull request as ready for review July 15, 2026 15:34

@cloud-fan cloud-fan 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.

0 blocking, 0 non-blocking, 0 nits.
Clean. BinByExec reuses PartitioningPreservingUnaryExecNode with the same outputExpressions = output idiom as ProjectExec and the aggregate execs, so the pass-through/scaled distinction falls out of the trait's output-set filter rather than needing special-casing.

No findings.

Verification

Traced the load-bearing correctness claim: a preserved HashPartitioning still holds across BIN BY's 1:N row multiplication. BIN BY runs under mapPartitionsInternal (never moves rows across partitions), and pass-through column values are identical across an input row's emitted sub-rows, so co-location on a pass-through key is preserved. The scaled-DISTRIBUTE case is correctly dropped: BinByResolution.scaledDistributeAttributes mints a fresh ExprId, so the child partitioning keyed on the original (pre-scale) column is absent from the output set and filtered out. The mixed case drops whole. All three are covered by the added tests, which reproduce the fresh-ExprId minting faithfully and assert on partitioning metadata directly.

@cloud-fan cloud-fan closed this in 5294834 Jul 15, 2026
cloud-fan pushed a commit that referenced this pull request Jul 15, 2026
### What changes were proposed in this pull request?

This PR makes `BinByExec` extend `PartitioningPreservingUnaryExecNode` so it reports an `outputPartitioning` derived from its child.

A child partitioning is kept only when its keys are in the operator's output: a partitioning on a pass-through column survives, while one on a scaled `DISTRIBUTE` column is dropped (that column has a fresh `ExprId` absent from the output). Keeping the pass-through case is safe because `BIN BY` transforms each partition independently and pass-through columns hold the same value across an input row's sub-rows.

### Why are the changes needed?

A downstream operator clustered on a pass-through column that the child already partitions on would otherwise get an unnecessary shuffle.

### Does this PR introduce _any_ user-facing change?

No. `BIN BY` is gated off by default (`spark.sql.binByRelationOperator.enabled`).

### How was this patch tested?

`ProjectedOrderingAndPartitioningSuite`: a pass-through key is preserved as `HashPartitioning`, a scaled `DISTRIBUTE` key is dropped to `UnknownPartitioning`, and a mixed key is dropped whole.

### Was this patch authored or co-authored using generative AI tooling?

Generated-by: Claude Code (Anthropic)

Closes #57275 from vranes/bin-by-output-partitioning.

Authored-by: Nikolina Vraneš <nikolina.vranes@databricks.com>
Signed-off-by: Wenchen Fan <wenchen@databricks.com>
(cherry picked from commit 5294834)
Signed-off-by: Wenchen Fan <wenchen@databricks.com>
@cloud-fan

Copy link
Copy Markdown
Contributor

Merge Summary:

Posted by merge_spark_pr.py

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

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants