SubhamSinghal opened a new pull request, #23870:
URL: https://github.com/apache/datafusion/pull/23870

    ## Which issue does this close?
   
   Part of #17427 (Make `PiecewiseMergeJoin` work in DataFusion). Adds 
`LeftSemi` / `LeftAnti` support, one of the epic's checklist items. Supersedes 
the stale #18392, taking the alternative approach that @2010YOUY01 suggested 
there (reuse the classic join path for generality) rather than a dedicated 
existence stream.
   
     ## Rationale for this change
   
   An inequality-correlated `EXISTS` / `NOT EXISTS` (e.g. `WHERE EXISTS (SELECT 
1 FROM r WHERE l.x < r.y)`) has no equi-key, so it decorrelates to a `LeftSemi` 
/ `LeftAnti` join with a single range predicate. Today `PiecewiseMergeJoinExec` 
rejects existence joins (`not_impl_err!`) and these queries fall back to 
`NestedLoopJoinExec`, which is O(n*m).
   
     Microbenchmark (20K × 20K rows, single inequality, 
`enable_piecewise_merge_join`
     on vs off), added in this PR as `piecewise_merge_join_semi_anti`:
   
     | Case                         | PWMJ     | NestedLoopJoin | Speedup |
     |------------------------------|----------|----------------|---------|
     | LeftSemi, high selectivity   | ~0.50 ms | ~75 ms         | ~150×   |
     | LeftAnti, high selectivity   | ~0.44 ms | ~75 ms         | ~170×   |
     | LeftSemi, low selectivity    | ~0.48 ms | ~76 ms         | ~158×   |
     | LeftAnti, low selectivity    | ~0.48 ms | ~75 ms         | ~155×   |
   
     ## What changes are included in this PR?
   
     **Existence joins (`LeftSemi` / `LeftAnti`) for `PiecewiseMergeJoin`:**
     - Route `LeftSemi` / `LeftAnti` with a single range predicate to 
`PiecewiseMergeJoinExec` in the physical planner (still gated behind 
`enable_piecewise_merge_join`, default `false`).
     - Reuse the classic scan: on the first match, mark the matching 
buffered-row suffix in the visited bitmap and emit from it in the final pass 
(`LeftSemi` = marked rows, `LeftAnti` = unmarked; NULL join keys are never 
marked, so they are correctly excluded from Semi and included in Anti). Only 
left-side columns are produced.
     - `RightSemi` / `RightAnti` / `Mark` remain unsupported (they require 
swapping the inputs); they are still rejected in `try_new` and excluded in the 
planner. Left as a follow-up.
     - Two small optimizations so existence marking stays O(buffered), not 
O(n*m): stop scanning a batch after the first match (the marked suffix is 
maximal), and a cross-batch low-water mark so later batches only mark 
not-yet-marked rows.
     - Updated the operator docstring to describe the implemented classic-reuse 
path and keep the min/max fast-path as a documented follow-up.
   
     ## Are these changes tested?
   
     Yes.
     - 33 unit tests in `classic_join.rs` covering `LeftSemi` / `LeftAnti` 
across `<`, `<=`, `>`, `>=`; NULL join keys; all-null streamed side; empty 
inputs; `Date32` keys; multi-batch and multi-partition streamed inputs; and the 
low-water-mark skip branch.
     - End-to-end SLT coverage in `pwmj.slt` for `EXISTS` / `NOT EXISTS` 
(including NULLs) with `EXPLAIN` assertions confirming the plan uses 
`PiecewiseMergeJoin`.
     - The multi-partition test also guards the final-pass counter fix.
   
     ## Are there any user-facing changes?
   
     No behaviour change by default: `enable_piecewise_merge_join` remains 
`false`. When enabled, single-range-predicate `LeftSemi` / `LeftAnti` joins are 
planned as `PiecewiseMergeJoin` instead of `NestedLoopJoin`. No API changes.


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: [email protected]

For queries about this service, please contact Infrastructure at:
[email protected]


---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to