Support broker segment pruning for colocated joins - #19174
Open
yashmayya wants to merge 2 commits into
Open
Conversation
A colocated join failed outright when a partition of one of its tables held no segments, with "Failed to find any segment for table: X, partition: N". Worker ids came from a running counter over the partitions that held data, so skipping an empty one would shift every later partition down a slot. Two tables each dropping a different empty partition could then end up with equal worker counts and be wired 1-to-1 onto mismatched partitions, losing rows with no error, which is why the assignment refused to continue at all. The stages tied together by direct exchanges now share one ordered list of partition classes, dropping only the classes that hold no data on any member. A class the group keeps but a member holds no data for gets a worker with no segments, placed on a server borrowed from a member that does hold that class so the exchange stays in process. The two sides of every direct exchange assert that they agree on the list. The broker publishes the partitions whose only segments are new and have no online replica. Those hold data that no server can serve as a whole, so they keep failing rather than being read as empty. A worker with no segments is charged against the query thread estimate like any other worker: it is dispatched and does run a leaf operator. The estimate therefore over-counts by two threads per such worker, which is conservative and only affects colocated joins over a partition space that is largely unpopulated. Those queries failed outright before, so there is no earlier estimate to compare against. Aggregation merge identity is deliberately not covered here. A leaf that scans nothing emits one identity row for an aggregation with no GROUP BY, but that predates this change: a worker whose segments are all pruned on the server already does the same. Padding raises how many such rows reach the merge without introducing the dependency, and the one aggregation that is not a true merge identity fails only when every worker is empty, which this change does not newly reach.
Codecov Report❌ Patch coverage is Additional details and impacted files@@ Coverage Diff @@
## master #19174 +/- ##
============================================
+ Coverage 66.57% 66.69% +0.12%
Complexity 1423 1423
============================================
Files 3441 3445 +4
Lines 218320 219061 +741
Branches 34737 34910 +173
============================================
+ Hits 145341 146100 +759
+ Misses 61251 61218 -33
- Partials 11728 11743 +15
Flags with carried forward coverage won't be shown. Click here to find out more. ☔ View full report in Codecov by Harness. 🚀 New features to boost your workflow:
|
yashmayya
force-pushed
the
broker-pruning-colocated-joins
branch
from
August 6, 2026 23:47
653aa15 to
ec4ac46
Compare
gortiz
self-requested a review
August 7, 2026 10:23
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.
Follow-up to #19166, which reduced a colocated join to the partition classes that hold data. This does the same for the classes that a filter empties, so a filtered colocated join runs on fewer workers and reaches fewer servers.
Only the default (logical) MSE planner is affected. The V2 physical optimizer already derives its partitions from a pruned routing table.
What this enables
A colocated join over two partitioned tables, with a filter on the partition key:
Both sides prune every partition class except 1 and 2. The group drops the rest. The result:
These cases get the reduction:
The 1-to-1 exchange survives the reduction. Every leaf of the group keeps one worker per surviving class, in the same order, so worker
kmeans the same class on every side.What this does not help
The common case is in this list, so it is worth stating plainly.
segmentPrunerTypes: ["partition"]. Pinot builds the partition pruner only when the routing config asks for it. Without it, nothing is pruned.getCandidateServersPerTablesignores the query and expands the dispatched set again. WithuseLeafServerForIntermediateStage=true, the reduction carries upward.Trade-offs
A class drops only when every member of the group prunes it. The alternative is to drop a class as soon as one side prunes it. That is wrong for a RIGHT join, a FULL join, a union, and an anti-join. In each of those, the other side still produces rows. The union rule needs no knowledge of the operator above. A new colocated operator therefore cannot break it in silence. The cost is the one-sided filter case above.
A surviving class dispatches all of its segments on every member. A member whose own filter excludes them still scans them. The server-side filter removes them again. This keeps the class on the same server it uses without pruning, so the exchange stays in process. A finer verdict inside a surviving class is possible later.
Planning costs one routing call per member. Only a leaf that carries a filter pays it. The result is cached per fragment, so the leaf assignment reuses it.
A sound proof of emptiness
The old verdict read "this partition is pruned" from the absence of its segments in the routing table. Absence has innocent causes. Instance selection can class a segment as optional. The server that holds a segment can leave the enabled server map. A segment can enter the partition metadata before it becomes selectable. Each of these loses matching rows.
This adds a planner-only entry point that reports which segments the pruners pruned:
Only presence in that set is a proof. Instance selection takes no part and there is no request id, so two leaves over one table and one filter cannot disagree.
MultiClusterRoutingManagercombines the set by intersection, because a proof holds only when every cluster that can route the segment pruned it.The ordinary partitioned leaf now uses the same proof. That path is strictly more conservative than before.
How to turn it off
No new flag. The query option
useBrokerPruningand the broker configpinot.broker.multistage.logical.planner.use.broker.pruningalready do it. With pruning off, every populated class keeps its worker, which is the behavior of #19166.Tests
WorkerManagerTestcovers both sides pruning and one side pruning. It also covers the all-pruned fallback, an unavailable segment, a routing failure and the kill switch. Two more cases cover padding together with reduction, and a self-join whose sides prune different classes.BrokerRoutingManagerTestandMultiClusterRoutingManagerTestcover the pruned set and the multi-cluster intersection.ColocatedJoinEmptyPartitionTestruns the filtered join end to end. It proves the 1-to-1 wiring at the reduced width. It also matches the rows against the same query without the colocation hint. A filter that matches nothing returns an empty result.The integration fixture had no
RoutingConfig, so it built no partition pruner. This adds one. Without it a filtered assertion proves nothing.Notes
numReplicas 2, so both servers hold every segment. The end-to-end tests assert worker count, segments queried, fan-out and receiver ids.WorkerManagerTestasserts the dispatched server set.