Skip to content

Broadcast the build side of a SortMergeJoinExec without converting to a hash join #1922

Description

@andygrove

Background

PR #1904 (closing #1679) added a static-planner optimization that, when one side of a SortMergeJoinExec fits under ballista.optimizer.broadcast_join_threshold_bytes, converts the join to a HashJoinExec(CollectLeft) and reuses the existing broadcast lowering. This avoids the two hash-partitioned shuffles a sort-merge join would otherwise require.

That approach changes the join operator (SMJ → hash join). A distinct, complementary optimization is to keep the SortMergeJoinExec and instead broadcast (replicate) its small build side to every probe task — the probe side stays in its natural partitioning and the merge-join semantics are preserved. This is closer to what Spark does: as @milenkovicm noted on PR #1904, Spark broadcasts the build side of a sort-merge join (observed in TPC-DS Q72 at SF10).

Motivation

Proposed work

  1. Spike: determine what a broadcast/replicated build input looks like for SortMergeJoinExec — the build side must still be sorted on the join key and materialized on every probe task, while the probe side keeps its natural partitioning (no join-key repartition).
  2. Wire it into both planners (static DefaultDistributedPlanner and the AQE join-selection path), gated by config, and compare against the convert-to-hash-join path from feat: broadcast small build side of SortMergeJoinExec in the static planner #1904.
  3. Benchmark under both AQE on and AQE off — TPC-H SF10 and the TPC-DS Q72 case @milenkovicm called out — with row-count verification.

References

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions