Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Stop copying LogicalPlan and Exprs in PushDownFilter (4%-6% faster planning) #10444

Merged
merged 3 commits into from May 17, 2024

Conversation

alamb
Copy link
Contributor

@alamb alamb commented May 10, 2024

Draft as it depends on

Which issue does this PR close?

Closes #10291

Rationale for this change

Follow on to #10366 from @dmitrybugakov ❤️

Make planning faster by removing clones in filter pushdown

What changes are included in this PR?

Rewrite the PushDownFilter to not copy things

Are these changes tested?

Functionally it is covered by existing tests (specifically there are unit tests in the module, the sqllogictest and tpcds planner tests)

Are there any user-facing changes?

There is no functional change

Performance improvement shows 4-6% faster for TPCH/TPDS planning

Details

++ critcmp main push_down_filter
group                                         main                                   push_down_filter
-----                                         ----                                   ----------------
logical_aggregate_with_join                   1.00  1212.9±18.64µs        ? ?/sec    1.00  1217.1±10.78µs        ? ?/sec
logical_plan_tpcds_all                        1.00    159.3±1.73ms        ? ?/sec    1.00    158.7±1.79ms        ? ?/sec
logical_plan_tpch_all                         1.01     17.0±0.19ms        ? ?/sec    1.00     16.9±0.18ms        ? ?/sec
logical_select_all_from_1000                  1.01     18.8±0.14ms        ? ?/sec    1.00     18.7±0.09ms        ? ?/sec
logical_select_one_from_700                   1.00    811.6±7.82µs        ? ?/sec    1.01   820.1±29.24µs        ? ?/sec
logical_trivial_join_high_numbered_columns    1.00    760.1±8.61µs        ? ?/sec    1.00   762.9±13.46µs        ? ?/sec
logical_trivial_join_low_numbered_columns     1.00    744.4±7.41µs        ? ?/sec    1.01    749.5±8.29µs        ? ?/sec
physical_plan_tpcds_all                       1.06   1359.1±7.59ms        ? ?/sec    1.00   1284.5±8.00ms        ? ?/sec
physical_plan_tpch_all                        1.04     92.1±1.28ms        ? ?/sec    1.00     88.3±1.23ms        ? ?/sec
physical_plan_tpch_q1                         1.09      5.1±0.08ms        ? ?/sec    1.00      4.7±0.08ms        ? ?/sec
physical_plan_tpch_q10                        1.05      4.4±0.09ms        ? ?/sec    1.00      4.2±0.08ms        ? ?/sec
physical_plan_tpch_q11                        1.07      4.0±0.08ms        ? ?/sec    1.00      3.7±0.07ms        ? ?/sec
physical_plan_tpch_q12                        1.05      3.1±0.05ms        ? ?/sec    1.00      2.9±0.05ms        ? ?/sec
physical_plan_tpch_q13                        1.04      2.1±0.04ms        ? ?/sec    1.00      2.1±0.04ms        ? ?/sec
physical_plan_tpch_q14                        1.10      2.8±0.05ms        ? ?/sec    1.00      2.5±0.05ms        ? ?/sec
physical_plan_tpch_q16                        1.05      3.8±0.09ms        ? ?/sec    1.00      3.6±0.07ms        ? ?/sec
physical_plan_tpch_q17                        1.01      3.6±0.06ms        ? ?/sec    1.00      3.5±0.08ms        ? ?/sec
physical_plan_tpch_q18                        1.04      4.0±0.06ms        ? ?/sec    1.00      3.8±0.09ms        ? ?/sec
physical_plan_tpch_q19                        1.11      6.3±0.07ms        ? ?/sec    1.00      5.7±0.08ms        ? ?/sec
physical_plan_tpch_q2                         1.05      7.9±0.06ms        ? ?/sec    1.00      7.6±0.07ms        ? ?/sec
physical_plan_tpch_q20                        1.01      4.5±0.09ms        ? ?/sec    1.00      4.5±0.09ms        ? ?/sec
physical_plan_tpch_q21                        1.05      6.2±0.07ms        ? ?/sec    1.00      6.0±0.09ms        ? ?/sec
physical_plan_tpch_q22                        1.04      3.4±0.07ms        ? ?/sec    1.00      3.3±0.07ms        ? ?/sec
physical_plan_tpch_q3                         1.05      3.2±0.06ms        ? ?/sec    1.00      3.0±0.05ms        ? ?/sec
physical_plan_tpch_q4                         1.05      2.4±0.05ms        ? ?/sec    1.00      2.2±0.04ms        ? ?/sec
physical_plan_tpch_q5                         1.04      4.5±0.06ms        ? ?/sec    1.00      4.4±0.07ms        ? ?/sec
physical_plan_tpch_q6                         1.07  1615.0±89.07µs        ? ?/sec    1.00  1505.8±20.04µs        ? ?/sec
physical_plan_tpch_q7                         1.03      5.8±0.07ms        ? ?/sec    1.00      5.6±0.07ms        ? ?/sec
physical_plan_tpch_q8                         1.05      7.4±0.08ms        ? ?/sec    1.00      7.1±0.09ms        ? ?/sec
physical_plan_tpch_q9                         1.06      5.7±0.08ms        ? ?/sec    1.00      5.4±0.07ms        ? ?/sec
physical_select_all_from_1000                 1.01     61.8±1.40ms        ? ?/sec    1.00     61.1±0.27ms        ? ?/sec
physical_select_one_from_700                  1.00      3.7±0.04ms        ? ?/sec    1.00      3.7±0.05ms        ? ?/sec```

</p>
</details> 

@github-actions github-actions bot added logical-expr Logical plan and expressions optimizer Optimizer rules labels May 10, 2024
@alamb alamb changed the title Stop copying LogicalPlan and Exprs in PushDownFilter Stop copying LogicalPlan and Exprs in PushDownFilter (4%-6% faster planning) May 10, 2024
@alamb alamb marked this pull request as ready for review May 13, 2024 13:17
datafusion/expr/src/expr.rs Outdated Show resolved Hide resolved
join_plan: &LogicalPlan,
left: &LogicalPlan,
right: &LogicalPlan,
inferred_join_predicates: Vec<Expr>,
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is refactored so that the Join is passed in, rather than a LogicalPlan and the embedded Join Plan as well as a reference to the embedded pieces

};
// Are there any new join predicates that can be inferred from the filter expressions?
let inferred_join_predicates =
infer_join_predicates(&join, &predicates, &on_filters)?;
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

pulled out to a function to make it easier to see what is going on -- the logic was not changed

};

let child_plan = filter.input.as_ref();
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Here is the core change -- instead of looking at the input by ref the PR now takes its ownership and then updates the accounting to avoid cloneing

},
LogicalPlan::CrossJoin(_) => Ok((true, true)),
_ => internal_err!("lr_is_preserved only valid for JOIN nodes"),
fn lr_is_preserved(join_type: JoinType) -> Result<(bool, bool)> {
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

the plan was always a join so rather than having to re-check the plan, I changed to simply take the JoinType

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

👍

predicates: &[Expr],
on_filters: &[Expr],
) -> Result<Vec<Expr>> {
if join.join_type != JoinType::Inner {
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this logic was refactored from above

@alamb alamb requested a review from jackwener May 15, 2024 18:58
@alamb
Copy link
Contributor Author

alamb commented May 15, 2024

@jackwener I know this is a fairly large PR, but I think you were the one who did the last major rework of this code. Do you happen to have any time to review this PR?

Copy link
Member

@jackwener jackwener left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A very nice job to me! Thank you @alamb .
Besides enhancing performance, I am pleased to see that the readability of this part of the code has significantly improved. During the PR review process, I found the entire workflow to be much clearer.

},
LogicalPlan::CrossJoin(_) => Ok((true, true)),
_ => internal_err!("lr_is_preserved only valid for JOIN nodes"),
fn lr_is_preserved(join_type: JoinType) -> Result<(bool, bool)> {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

👍

Comment on lines +977 to +980
fn insert_below(
plan: LogicalPlan,
new_child: LogicalPlan,
) -> Result<Transformed<LogicalPlan>> {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's a great common method to me👍

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe I should pull it into optimizer/utils 🤔

Copy link
Contributor Author

@alamb alamb left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you very much for the review @jackwener 🙏

Comment on lines +977 to +980
fn insert_below(
plan: LogicalPlan,
new_child: LogicalPlan,
) -> Result<Transformed<LogicalPlan>> {
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe I should pull it into optimizer/utils 🤔

@alamb alamb merged commit 87169f0 into apache:main May 17, 2024
23 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
logical-expr Logical plan and expressions optimizer Optimizer rules
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Stop copying LogicalPlan and Exprs in PushDownFilter
2 participants