Commit 7fa6e21
authored
Skip map_expressions rebuild for Extension nodes with empty expressions (apache#21701)
## Which issue does this PR close?
- Closes apache#21700.
## Rationale for this change
When an Extension node has no expressions, `map_expressions` was still
cloning all inputs and calling `with_exprs_and_inputs` to reconstruct
the node — wasted work since there are no expressions to transform. This
is common for Extension nodes like view matching candidates that carry
multiple children but no expressions.
## What changes are included in this PR?
1. **Code change** (`datafusion/expr/src/logical_plan/tree_node.rs`):
Add early return when `node.expressions()` is empty, skipping the clone
+ rebuild path.
2. **Micro-benchmark** (`datafusion/expr/benches/map_expressions.rs`):
Criterion benchmark comparing `map_expressions` on Extension nodes with
and without expressions, varying the number of children (1, 3, 5, 10).
## Are these changes tested?
Yes — existing tests pass, and the new benchmark validates the
optimization.
Benchmark results:
| Children | no_expr (optimized) | with_expr (rebuild) | Speedup |
|----------|--------------------|--------------------|---------|
| 1 | 24 ns | 167 ns | 7x |
| 3 | 23 ns | 192 ns | 8x |
| 5 | 23 ns | 181 ns | 8x |
| 10 | 24 ns | 216 ns | 9x |
The `no_expr` path is constant time regardless of children count.
In a real optimizer pipeline (~15 rules × 5-child Extension), this saves
~2.4 us per optimization pass.
## Next step
A more general optimization would be to change
`UserDefinedLogicalNode::expressions()` to return references (`&[Expr]`)
instead of cloned `Vec<Expr>`, and only clone + rebuild when the
transform actually modifies an expression. This would avoid the clone +
`with_exprs_and_inputs` rebuild even for non-empty expression lists when
the transform is a no-op. Added a TODO comment in the code for this
direction. This would be a larger API change, so the empty-expressions
shortcut is a pragmatic first step.
## Are there any user-facing changes?
No — purely internal optimization. No API changes.1 parent 65f337d commit 7fa6e21
2 files changed
Lines changed: 68 additions & 65 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
584 | 584 | | |
585 | 585 | | |
586 | 586 | | |
587 | | - | |
588 | | - | |
589 | | - | |
590 | | - | |
591 | | - | |
592 | | - | |
593 | | - | |
594 | | - | |
595 | | - | |
596 | | - | |
597 | | - | |
| 587 | + | |
| 588 | + | |
| 589 | + | |
| 590 | + | |
| 591 | + | |
| 592 | + | |
| 593 | + | |
| 594 | + | |
| 595 | + | |
| 596 | + | |
| 597 | + | |
| 598 | + | |
| 599 | + | |
| 600 | + | |
| 601 | + | |
| 602 | + | |
| 603 | + | |
| 604 | + | |
| 605 | + | |
| 606 | + | |
| 607 | + | |
| 608 | + | |
| 609 | + | |
598 | 610 | | |
599 | 611 | | |
600 | 612 | | |
| |||
0 commit comments