Add case-heavy LEFT JOIN benchmark and debug timing/logging for PushDownFilter hot paths#20664
Add case-heavy LEFT JOIN benchmark and debug timing/logging for PushDownFilter hot paths#20664kosiew merged 6 commits intoapache:mainfrom
Conversation
| query.push_str(" AND "); | ||
| } | ||
|
|
||
| let mut expr = format!("length(l.c{})", i % 20); |
There was a problem hiding this comment.
I don't think we really want a benchmark for the case expression.
We want to optimize for the evaluation cost of the filter during pushdown, so perhaps it could be written not using a large case expression as is done currently or adaptive removing filters, etc.
There was a problem hiding this comment.
So the TPC-H/TPC-DS one is already a good one to optimize for.
There was a problem hiding this comment.
don't think we really want a benchmark for the case expression.
We want to optimize for the evaluation cost of the filter during pushdown, so perhaps it could be written not using a large case expression as is done currently or adaptive removing filters, etc.
I believe that you fear that by using a huge CASE expression we might be tuning for an unrealistic “case expression” workload instead of the more common cost of pushing filters through joins.
The benchmark uses CASE because that form triggered a profiler hotspot in PushDownFilter — the nullability/type‑inference codepath for filters on non‑inner joins. I don’t believe real‑world queries typically look like this, so the presence of CASE is purely a convenient way to exercise that particular expensive planner path, not the target of optimization.
To make this clear and avoid overfitting, I’m going to treat the CASE variant as a narrowly scoped micro‑benchmark and add a companion LEFT JOIN query with a simple predicate instead of a CASE.
With both in place we can separate:
- the baseline cost of pushing a filter through a join, and
- the extra work incurred when a CASE expression forces nullability inference.
That way the benchmark remains useful for optimization while still reflecting more general planner behaviour.
So the TPC-H/TPC-DS one is already a good one to optimize for.
Agreed. TPC-H/TPC-DS should remain the primary goal for optimization value and regression detection.
The intent here is to complement those suites with a deterministic micro-benchmark that isolates known planner hotspot; macro benchmarks are still required to verify end-to-end relevance and prevent narrow wins.
There was a problem hiding this comment.
Hm I didn't realize the issue is about planning (not about evaluation cost / pushdown per se), sorry about that!
Perhaps this would make sense to move into the planning benchmarks instead?
There was a problem hiding this comment.
Oh wait - it already is 🙈
|
@adriangb FYI Can we reconsider creating a large crazy large expression for the dynamic filters? now the size of the dynamic expression is something like
Perhaps create a |
I'm open to suggestions. We should find a solution that keeps the performance wins for small number of join keys / CPUs without degrading for large combinations of those. My hope was that |
|
@Dandandan |
Which issue does this PR close?
Rationale for this change
The
PushDownFilteroptimizer rule shows a severe planner-time performance pathology in thesql_planner_extendedbenchmark, where profiling indicates it dominates total planning CPU time and repeatedly recomputes expression types.This PR adds a deterministic, CASE-heavy LEFT JOIN benchmark to reliably reproduce the worst-case behavior and introduces lightweight debug-only timing + counters inside
push_down_filterto make it easier to pinpoint expensive sub-sections (e.g. predicate simplification and join predicate inference) during profiling.What changes are included in this PR?
Benchmark: add a deterministic CASE-heavy LEFT JOIN workload
Adds
build_case_heavy_left_join_queryand helpers to construct a CASE-nested predicate chain over aLEFT JOIN.Adds a new benchmark
logical_plan_optimize_case_heavy_left_jointo stress planning/optimization time.Adds an A/B benchmark group
push_down_filter_case_heavy_left_join_abthat sweeps predicate counts and CASE depth, comparing:push_down_filterenabledpush_down_filterremovedOptimizer instrumentation (debug-only)
Adds a small
with_debug_timinghelper gated bylog_enabled!(Debug)to record microsecond timings for specific sections.Instruments and logs:
infer_join_predicatessimplify_predicateson_filters, inferred join predicatesAre these changes tested?
No new unit/integration tests were added because this PR is focused on benchmarking and debug-only instrumentation rather than changing optimizer semantics.
Coverage is provided by:
sql_planner_extendedbenchmarkpush_down_filter) produce optimized plans without errorsRUST_LOG=debugto confirm timing sections and counters emit as expectedAre there any user-facing changes?
RUST_LOGenables Debug for the relevant modules).LLM-generated code disclosure
This PR includes LLM-generated code and comments. All LLM-generated content has been manually reviewed and tested.