Repository navigation
[experiment] Runtime hash join build-side selection on StageBoundary - #12
Draft
avantgardnerio wants to merge 2 commits into
Draft
avantgardnerio wants to merge 2 commits into
avantgardnerio wants to merge 2 commits into
Conversation
Experimental, not for merge. Adds ThresholdBoundaryExec and an AdaptiveJoinExec driver, plus the AdaptiveJoinBuildSide optimizer rule behind datafusion.optimizer.adaptive_join_build_side (off by default). The driver races both join inputs, doubling a byte limit, until one input finishes and the other has at least as many rows, then swaps the join so the input with fewer rows becomes the build side. TPC-H SF100 findings (32 cores, results identical with the flag on/off): - Q9's two inverted joins swap. Its minimum memory limit drops from 14G to 9G and peak RSS from 17.0G to 12.2G, with no slowdown. - No meaningful speedup: the whole suite is neutral to 3.6% slower. - At a 10G limit, Q9 is rescued but Q7 starts failing. Co-Authored-By: Claude Opus 5.5 <[email protected]>
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.
Which issue does this PR close?
Not meant for merge. This is an experiment on top of apache#25798 to test the idea in apache#25798 (comment): use
StageBoundaryto pick a hash join's build side at runtime. Related to apache#23194.Rationale for this change
The planner chooses a hash join's build side from static statistics, which are often wrong. This PR checks whether the
StageBoundaryAPI is enough to fix that choice at runtime on a real benchmark.What changes are included in this PR?
Hack-quality code, organized as two commits:
demoExecutionPlan::as_boundary(), defaulting toNone, so a driver can find boundaries by walking the plan.StageBoundary::progress(partition) -> Option<StageProgress>, which reports rows, bytes and whether the input finished. It also changesis_readyto mean "safe to inspect".cargo run --release --example execution_monitoring -- adaptive_join.hack: runtime hash join build-side selection driverThresholdBoundaryExecbuffers each partition up to a byte limit that the driver can raise. Buffered memory is charged to the memory pool.AdaptiveJoinExecsits at the plan root. Before executing the plan, it resolves joins from the bottom up. For each join, it races both inputs, doubling the limit, until one input finishes and the other is known to have at least as many rows. If the input that finished is the probe side, it swaps the join.AdaptiveJoinBuildSideoptimizer rule is behinddatafusion.optimizer.adaptive_join_build_side, which is off by default.What is the testing strategy for this PR?
There are two unit tests for the swap safety check. Beyond those, it was tested by running TPC-H at SF100 on a 32-core box with
dfbench, flag off and on.Correctness: Q4, Q8, Q9, Q10, Q15 and Q22 return identical results with the flag off and on.
Memory: the clearest result is on Q9, where the planner puts 150M-row and 80M-row inputs on the build side against a 32M-row probe.
--memory-limitthat completesSpeed: there is no meaningful speedup. The full suite ranges from neutral to 3.6% slower, because each join now waits for both of its inputs to be drained before it starts. The toy example is 6x faster, but only because its small side fits in cache and it runs on a single partition. TPC-H's misestimated joins all have two large inputs.
Whole suite at a 10G limit: 20 of 22 queries pass with the flag off and with it on. The flag rescues Q9 but makes Q7 fail.
Things this turned up:
HashJoinExeckeeps reporting hash partitioning on its join keys after its embedded projection drops them.get_array_memory_sizecounts StringView data buffers once per batch that shares them, so after aRepartitionExecit overcounts by up to 32x.Are there any user-facing changes?
Two new experimental config options, both off by default. The config docs and
information_schematest have not been updated.🤖 Generated with Claude Code