Is your feature request related to a problem or challenge?
Broken out from #9577 where @mustafasrepo @comphead and @jayzhan211 and I were discussing optimizer performance
TLDR is that the datafusion optimizer is slow. When I did some profiling locally by running the following
cargo bench --bench sql_planner -- physical_plan_tpch_all
My analysis is that almost 40% of the planning time is spent in SimplifyExprs and CommonSubexprEliminate and most of that time is related to copying expressions from what I can tell

While those passes themselves internally make a bunch of clones, which we are improving (e.g. @jayzhan211 on #9628) I think there is a more fundamental structural problem
I think a core challenge is that the OptimizerRule trait pretty much requires copying Exprs on each pass, as it gets a &LogicalPlan input, but produces a LogicalPlan output
// Required methods
fn try_optimize(
&self,
plan: &LogicalPlan,
config: &dyn OptimizerConfig
) -> Result<Option<LogicalPlan>, DataFusionError>;
This mean any pass that works on Exprs must clone all Exprs (by calling LogicalPlan::expressions()) rewrite them, and then then create a new LogicalPlan with those new Exprs.
Here is that pattern in the expression simplifier:
https://github.com/apache/arrow-datafusion/blob/0eec5f8e1d0f55e48f5cdc628fbb5ddd89b91512/datafusion/optimizer/src/simplify_expressions/simplify_exprs.rs#L112-L123
Describe the solution you'd like
Find some way to avoid clone'ing exprs during LogicalPlan rewrite
Update: here are the tasks:
Infrastructure Preparation
Update OptimizerRules to avoid copying
Update AnalyzerRules to avoid copying
Update Other to avoid copying
Describe alternatives you've considered
No response
Additional context
We have talked about various other ways to reduce copying of LogicalPlans as well as its challenges in other tickets:
Is your feature request related to a problem or challenge?
Broken out from #9577 where @mustafasrepo @comphead and @jayzhan211 and I were discussing optimizer performance
TLDR is that the datafusion optimizer is slow. When I did some profiling locally by running the following
My analysis is that almost 40% of the planning time is spent in SimplifyExprs and CommonSubexprEliminate and most of that time is related to copying expressions from what I can tell
While those passes themselves internally make a bunch of clones, which we are improving (e.g. @jayzhan211 on #9628) I think there is a more fundamental structural problem
I think a core challenge is that the OptimizerRule trait pretty much requires copying
Exprson each pass, as it gets a&LogicalPlaninput, but produces aLogicalPlanoutputThis mean any pass that works on
ExprsmustcloneallExprs(by callingLogicalPlan::expressions()) rewrite them, and then then create a newLogicalPlanwith those new Exprs.Here is that pattern in the expression simplifier:
https://github.com/apache/arrow-datafusion/blob/0eec5f8e1d0f55e48f5cdc628fbb5ddd89b91512/datafusion/optimizer/src/simplify_expressions/simplify_exprs.rs#L112-L123
Describe the solution you'd like
Find some way to avoid clone'ing exprs during LogicalPlan rewrite
Update: here are the tasks:
Infrastructure Preparation
Optimizerto use owned plans andTreeNodeAPI (10% faster planning) #9948LogicalPlan::clone()inLogicalPlan::map_childrenwhen possible #9999Update
OptimizerRules to avoid copyingSimplifyExpressions: IntroduceOptimizerRule::rewriteto rewrite in place, rewriteExprSimplifier(20% faster planning) #9954CommonSubexprEliminate: Stop copyingExprs and LogicalPlans so much during Common Subexpression Elimination #9873DecorrelatePredicateSubquery: Stop copying LogicalPlan and Exprs inDecorrelatePredicateSubquery#10289EliminateCrossJoin: Stop copying LogicalPlan and Exprs inEliminateCrossJoin#10287EliminateDuplicatedExpr: refactorEliminateDuplicatedExproptimizer pass to avoid clone #10218EliminateFilter: Stop copying LogicalPlan and Exprs inEliminateFilter#10288EliminateJoin: Implement rewrite for EliminateOneUnion and EliminateJoin #10184EliminateLimit: Stop copying LogicalPlan and Exprs inEliminateLimit#10212EliminateNestedUnion: Stop copying LogicalPlan and Exprs inEliminateNestedUnion#10296EliminateOneUnion: Implement rewrite for EliminateOneUnion and EliminateJoin #10184EliminateOuterJoin: RefactorEliminateOuterJointo implementOptimizerRule::rewrite()#10081ExtractEquijoinPredicate: implement rewrite for ExtractEquijoinPredicate and avoid clone in filter #10165FilterNullJoinKeysimplement rewrite for FilterNullJoinKeys #10166OptimizeProjections: Stop copying LogicalPlan and Exprs inOptimizeProjections#10209PropagateEmptyRelation: Stop copying LogicalPlan and Exprs inPropagateEmptyRelation#10290PushDownFilter: Stop copying LogicalPlan and Exprs inPushDownFilter#10291PushDownLimit: Stop copying LogicalPlan and Exprs inPushDownLimit#10292ReplaceDistinctWithAggregate: Stop copying LogicalPlan and Exprs inReplaceDistinctWithAggregate#10293RewriteDisjunctivePredicate: Stop copying LogicalPlan and Exprs inRewriteDisjunctivePredicate#10213ScalarSubqueryToJoin: Stop copying LogicalPlan and Exprs inScalarSubqueryToJoin#10294SingleDistinctToGroupBy: Stop copying LogicalPlan and Exprs inSingleDistinctToGroupBy#10295UnwrapCastInComparisonRefactorUnwrapCastInComparisonto implementOptimizerRule::rewrite()#10087 / RefactorUnwrapCastInComparisonto removeExprclones #10115Update
AnalyzerRules to avoid copyingAnalyzerMisc: Minor: Avoid copying all expressions inAnalzyer/check_plan#9974InlineTableScan: Avoid copies inInlineTableScanvia TreeNode API #10038ApplyFunctionRewrites: fixNamedStructField should be rewritten in OperatorToFunctionin subquery regression (changeApplyFunctionRewritesto use TreeNode API #10032TypeCoercion: Stop copying LogicalPlan and Exprs inTypeCoercion#10210TypeCoercionmore: Onyl recompute schema inTypeCoercionwhen necessary #10365CountWildcardRule: (needs a little reworking to avoid clones) Avoid copies inCountWildcardRulevia TreeNode API #10066Update Other to avoid copying
LogicalPlan::with_param_values#10016Describe alternatives you've considered
No response
Additional context
We have talked about various other ways to reduce copying of LogicalPlans as well as its challenges in other tickets:
Boxes withArcin theExprenum. #9577