refactor join-key equality filtering - #23843
Conversation
Codecov Report❌ Patch coverage is
Additional details and impacted files@@ Coverage Diff @@
## main #23843 +/- ##
=======================================
Coverage ? 80.86%
=======================================
Files ? 1101
Lines ? 375002
Branches ? 375002
=======================================
Hits ? 303234
Misses ? 53677
Partials ? 18091 ☔ View full report in Codecov by Harness. 🚀 New features to boost your workflow:
|
c19467c to
a7da3b0
Compare
There was a problem hiding this comment.
@shehab-ali
Thanks for working on this!
I have one small suggestion that could help make this a bit more robust against future regressions.
| let mut right_filtered = Vec::with_capacity(indices_right.len()); | ||
|
|
||
| let filter_builder = FilterBuilder::new(&equal).optimize().build(); | ||
| for (left, right) in indices_left.values().iter().zip(indices_right.values()) { |
There was a problem hiding this comment.
indices_left and indices_right are expected to be parallel candidate pair arrays, but this loop now uses zip, which would silently truncate if that invariant were ever broken.
Would it make sense to add a debug_assert_eq!(indices_left.len(), indices_right.len()) (or return an internal error) before the loop? That way, if a future caller accidentally violates the invariant, it will fail loudly instead of quietly dropping candidate pairs.
There was a problem hiding this comment.
good call, I added internal error for that case. Lmk if it looks good. thanks!
|
run benchmarks hj |
|
🤖 Benchmark running (GKE) | trigger CPU Details (lscpu)Comparing shehab/hashjoin-filter-keys (19ad65b) to f33dcec (merge-base) diff Run configurationrun benchmark hjResults will be posted here when complete File an issue against this benchmark runner |
|
🤖 Benchmark completed (GKE) | trigger Instance: Comparing shehab/hashjoin-filter-keys (19ad65b) to f33dcec (merge-base) diff Run configurationrun benchmark hjCPU Details (lscpu)Details
Resource Usagehj — base (merge-base)
hj — branch
File an issue against this benchmark runner |
|
Do you know why Q24,Q25 were not included?
Wondering if it is expected that Q23 has no perf improvement 🤔 edit: (for Q23) I think the thing that made it slow were the comparisons in |
|
I tried to target the Q23 case (single column refactoring) so I did this optimization in this commit #24067 and it's looking much better. Q24 and Q25 improvement is preserved and Q23 is ~10% faster on average |
|
run benchmark hj |
|
🤖 Benchmark running (GKE) | trigger CPU Details (lscpu)Comparing shehab/hashjoin-filter-keys (19ad65b) to f33dcec (merge-base) diff Run configurationrun benchmark hjResults will be posted here when complete File an issue against this benchmark runner |
|
🤖 Benchmark completed (GKE) | trigger Instance: Comparing shehab/hashjoin-filter-keys (19ad65b) to f33dcec (merge-base) diff Run configurationrun benchmark hjCPU Details (lscpu)Details
Resource Usagehj — base (merge-base)
hj — branch
File an issue against this benchmark runner |
Can you investigate why performance has regressed? |
Summary
Simplified and sped up candidate-pair equality filtering by eliminating per-row type dispatch and by using a pre-built comparator that respects
NullEqualitysemantics.Added targeted hash-join microbenchmarks to exercise high-fanout and single hot bucket join cases with long string keys and multi column keys.
Description
Before this change, hash join probing produced candidate build/probe row-index pairs and then equal_rows_arr validated those pairs by materializing temporary key arrays, comparing those arrays, building a boolean mask, and filtering the candidate indices.
After this change,
equal_rows_arrvalidates candidate pairs by comparing the original key arrays directly by row index usingJoinKeyComparator, then appending only matching candidate indices to the output arrays. It also now checks that the input shapes are valid before doing that work.Where This Happens in Hash Join
During hash join probing, DataFusion first asks the join hash map for candidate build/probe index pairs. Those pairs are still “candidate” matches because the hash table is based on hash values, so DataFusion must confirm that the actual join-key values are equal.
Before
After
This should particularly help workloads where:
Benchmark Performance
In #23980, we added new Q24 and Q25 benchmarksto make this behavior visible:
These benchmarks are meant to show whether future changes improve this exact candidate-pair validation path which replicate the hot partition case, not just generic hash join performance.
Testing
cargo testand the new teststest_equal_rows_arr_filters_candidate_pairsandtest_equal_rows_arr_respects_null_equalitypassed.