Skip to content

feat: make StatisticsRegistry the default operator-statistics path - #23651

Open
asolimando wants to merge 16 commits into
apache:mainfrom
asolimando:asolimando/statistics-registry-default
Open

feat: make StatisticsRegistry the default operator-statistics path#23651
asolimando wants to merge 16 commits into
apache:mainfrom
asolimando:asolimando/statistics-registry-default

Conversation

@asolimando

@asolimando asolimando commented Jul 16, 2026

Copy link
Copy Markdown
Member

Which issue does this PR close?

Rationale for this change

#23051 unified statistics into one StatisticsContext walk. This folds the
previously opt-in StatisticsRegistry (#21483) into that walk as the default, so
providers are consulted inline and use_statistics_registry is no longer needed.
Consumed today by join ordering and EXPLAIN; more CBO rules are follow-up.

What changes are included in this PR?

  • Consult the provider chain in the StatisticsContext walk (first Computed
    wins, else statistics_from_inputs); used by join_selection.
  • Deprecate use_statistics_registry (ignored, warns) and
    DefaultStatisticsProvider; add partition-aware
    StatisticsProvider::compute_statistics_with_args.
  • Propagate provider Extensions through the walk via a side cache (no cost
    without providers); add StatisticsContext::compute_extended, deprecate
    StatisticsRegistry::compute/compute_base.
  • EXPLAIN and EXPLAIN ANALYZE show_statistics now reflect the session registry.
  • Add the join_reorder example.

Are these changes tested?

Unit tests, statistics_registry.slt, the example, the full extended suite, and
compute_statistics at benchmark parity.

Are there any user-facing changes?

  • use_statistics_registry deprecated and ignored (default behavior unchanged).
  • StatisticsRegistry::compute/compute_base deprecated (55.0.0) for
    StatisticsContext; compute_extended added; DefaultStatisticsProvider
    deprecated. Nothing removed. See the 55.0.0 upgrade guide.

Disclaimer: I used AI to assist in the code generation, I have manually reviewed the output and it matches my intention and understanding.

@github-actions github-actions Bot added documentation Improvements or additions to documentation optimizer Optimizer rules sqllogictest SQL Logic Tests (.slt) common Related to common crate physical-plan Changes to the physical-plan crate labels Jul 16, 2026
@github-actions

github-actions Bot commented Jul 16, 2026

Copy link
Copy Markdown

Thank you for opening this pull request!

Reviewer note: cargo-semver-checks reported the current version number is not SemVer-compatible with the changes in this pull request (compared against the base branch).

Details
     Cloning apache/main
    Building datafusion v54.1.0 (current)
       Built [  99.961s] (current)
     Parsing datafusion v54.1.0 (current)
      Parsed [   0.032s] (current)
    Building datafusion v54.1.0 (baseline)
       Built [  99.597s] (baseline)
     Parsing datafusion v54.1.0 (baseline)
      Parsed [   0.032s] (baseline)
    Checking datafusion v54.1.0 -> v54.1.0 (no change; assume patch)
     Checked [   0.726s] 223 checks: 223 pass, 30 skip
     Summary no semver update required
    Finished [ 202.864s] datafusion
    Building datafusion-common v54.1.0 (current)
       Built [  32.276s] (current)
     Parsing datafusion-common v54.1.0 (current)
      Parsed [   0.058s] (current)
    Building datafusion-common v54.1.0 (baseline)
       Built [  32.328s] (baseline)
     Parsing datafusion-common v54.1.0 (baseline)
      Parsed [   0.059s] (baseline)
    Checking datafusion-common v54.1.0 -> v54.1.0 (no change; assume patch)
     Checked [   0.743s] 223 checks: 223 pass, 30 skip
     Summary no semver update required
    Finished [  66.675s] datafusion-common
    Building datafusion-physical-optimizer v54.1.0 (current)
       Built [  38.877s] (current)
     Parsing datafusion-physical-optimizer v54.1.0 (current)
      Parsed [   0.020s] (current)
    Building datafusion-physical-optimizer v54.1.0 (baseline)
       Built [  38.637s] (baseline)
     Parsing datafusion-physical-optimizer v54.1.0 (baseline)
      Parsed [   0.021s] (baseline)
    Checking datafusion-physical-optimizer v54.1.0 -> v54.1.0 (no change; assume patch)
     Checked [   0.133s] 223 checks: 223 pass, 30 skip
     Summary no semver update required
    Finished [  78.934s] datafusion-physical-optimizer
    Building datafusion-physical-plan v54.1.0 (current)
       Built [  35.818s] (current)
     Parsing datafusion-physical-plan v54.1.0 (current)
      Parsed [   0.135s] (current)
    Building datafusion-physical-plan v54.1.0 (baseline)
       Built [  35.618s] (baseline)
     Parsing datafusion-physical-plan v54.1.0 (baseline)
      Parsed [   0.138s] (baseline)
    Checking datafusion-physical-plan v54.1.0 -> v54.1.0 (no change; assume patch)
     Checked [   0.741s] 223 checks: 221 pass, 2 fail, 0 warn, 30 skip

--- failure type_marked_deprecated: #[deprecated] added on type ---

Description:
A type is now #[deprecated]. Downstream crates will get a compiler warning when using this type.
        ref: https://doc.rust-lang.org/reference/attributes/diagnostics.html#the-deprecated-attribute
       impl: https://github.com/obi1kenobi/cargo-semver-checks/tree/v0.49.0/src/lints/type_marked_deprecated.ron

Failed in:
  Struct DefaultStatisticsProvider in /home/runner/work/datafusion/datafusion/datafusion/physical-plan/src/operator_statistics/mod.rs:337

--- failure type_method_marked_deprecated: type method #[deprecated] added ---

Description:
A type method is now #[deprecated]. Downstream crates will get a compiler warning when using this method.
        ref: https://doc.rust-lang.org/reference/attributes/diagnostics.html#the-deprecated-attribute
       impl: https://github.com/obi1kenobi/cargo-semver-checks/tree/v0.49.0/src/lints/type_method_marked_deprecated.ron

Failed in:
  method datafusion_physical_plan::operator_statistics::StatisticsRegistry::compute in /home/runner/work/datafusion/datafusion/datafusion/physical-plan/src/operator_statistics/mod.rs:442
  method datafusion_physical_plan::operator_statistics::StatisticsRegistry::compute_base in /home/runner/work/datafusion/datafusion/datafusion/physical-plan/src/operator_statistics/mod.rs:456

     Summary semver requires new minor version: 0 major and 2 minor checks failed
    Finished [  73.884s] datafusion-physical-plan
    Building datafusion-sqllogictest v54.1.0 (current)
       Built [ 170.692s] (current)
     Parsing datafusion-sqllogictest v54.1.0 (current)
      Parsed [   0.020s] (current)
    Building datafusion-sqllogictest v54.1.0 (baseline)
       Built [ 171.741s] (baseline)
     Parsing datafusion-sqllogictest v54.1.0 (baseline)
      Parsed [   0.021s] (baseline)
    Checking datafusion-sqllogictest v54.1.0 -> v54.1.0 (no change; assume patch)
     Checked [   0.099s] 223 checks: 223 pass, 30 skip
     Summary no semver update required
    Finished [ 345.425s] datafusion-sqllogictest

@github-actions github-actions Bot added the auto detected api change Auto detected API change label Jul 16, 2026
@codecov-commenter

codecov-commenter commented Jul 16, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 80.33033% with 131 lines in your changes missing coverage. Please review.
✅ Project coverage is 80.85%. Comparing base (8fbbfdc) to head (08845ef).
⚠️ Report is 39 commits behind head on main.

Files with missing lines Patch % Lines
...usion/physical-plan/src/operator_statistics/mod.rs 71.14% 66 Missing and 52 partials ⚠️
datafusion/physical-plan/src/statistics.rs 93.78% 8 Missing and 3 partials ⚠️
datafusion/physical-plan/src/analyze.rs 83.33% 2 Missing ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##             main   #23651      +/-   ##
==========================================
+ Coverage   80.69%   80.85%   +0.15%     
==========================================
  Files        1095     1098       +3     
  Lines      372626   374693    +2067     
  Branches   372626   374693    +2067     
==========================================
+ Hits       300707   302956    +2249     
+ Misses      53968    53679     -289     
- Partials    17951    18058     +107     

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

@asolimando
asolimando force-pushed the asolimando/statistics-registry-default branch from 1f2d39d to 38d5bb1 Compare July 16, 2026 20:19
StatisticsContext (the single statistics walk, apache#23051) now consults the StatisticsRegistry (apache#21483) at each node before falling back to the operator's statistics_from_inputs, using the provider result's base Statistics. The registry is always-on: datafusion.optimizer.use_statistics_registry is deprecated and ignored (register providers on the SessionState instead). The now-redundant DefaultStatisticsProvider is deprecated, since the walk falls back natively.
The walk keeps core `Statistics` as its currency; a per-walk side cache
carries provider `Extensions` separately, so a walk with no providers has
no per-node overhead. A provider's `Computed` extensions are cached and
reach parent-node providers as their `child_stats`; the built-in
`statistics_from_inputs` fallback yields none, so extensions survive only
across an unbroken chain of provider-handled nodes.

Adds `StatisticsContext::compute_extended` (statistics + extensions)
alongside `compute` (core statistics only). `StatisticsRegistry::compute`
preserves extensions again; it and `compute_base` are deprecated in favor
of `StatisticsContext`.
EXPLAIN ... show_statistics computed statistics with an empty registry, so registered providers were not reflected in the statistics column. Thread the session's StatisticsRegistry into the displayable plan; the column now reflects provider-supplied estimates when providers are registered, and is unchanged when none are.
A runnable example showing a StatisticsProvider that supplies and refines column statistics (post-filter distinct count via the survival formula) to flip a join's build side, with a before/after EXPLAIN.
@asolimando
asolimando force-pushed the asolimando/statistics-registry-default branch from 38d5bb1 to ded4292 Compare July 17, 2026 18:38
@github-actions github-actions Bot added the core Core DataFusion crate label Jul 17, 2026
STORED AS PARQUET
LOCATION 'test_files/scratch/statistics_registry/dim_small.parquet';

# -- Without registry --------------------------------------------------------

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

Having removed use_statistics_registry config knob means the registry can't be turned off within an SLT. The no-provider path is covered by existing tests indirectly, and the with/without contrast now lives in the join_reorder example

}
struct StatsCache {
statistics: HashMap<CacheKey, Arc<Statistics>>,
extensions: HashMap<CacheKey, Extensions>,

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

I kept https://github.com/apache/datafusion/pull/23651/changes#diff-149914d58cc354ddd4d84e283de4f8f07f3295b39137d850b3344448d4f6dc7a separated on purpose in case reviewers prefer to drop it from this PR.

The reason to have two caches is that caching on ExtendedStatistics at every node regressed the compute_statistics benchmark ~6% to 28% (median ~13%) on the no-provider path (a wrapper allocation per node).

The committed version keeps core Statistics in the walk and holds Extensions in a side map, populated only when a provider returns some. Benchmark parity when no providers are registered, extensions still reach parent-node providers.

I think this commit is worth keeping for feature parity w.r.t. StatisticsRegistry as existing today.

metric_types: self.metric_types,
metric_categories: self.metric_categories,
format: self.format,
statistics_registry: self.statistics_registry,

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

The registry here is needed to keep EXPLAIN ANALYZE and EXPLAIN in sync when statistics providers are in use.

@asolimando
asolimando marked this pull request as ready for review July 17, 2026 19:30
@asolimando

Copy link
Copy Markdown
Member Author

As discussed in #21122 (comment), making StatisticsRegistry part of the default path was suggested by @alamb, who also suggested to showcase it via an example, which I have added, showing a better plan (join build/probe flip) over built-in defaults, via a statistics provider.

cc:

Note: the diff reads large (+1055 / -332), but ~620 of the added lines are examples and tests, ~38 are docs. The core change is ~400 lines, which goes down to a more reasonable ~300 if you exclude mechanical fixes.

@kosiew kosiew left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

@asolimando
Thanks for working on this.

I left two small suggestions to reduce duplication and make future display-related changes easier to maintain.

Comment thread datafusion/core/src/physical_planner.rs Outdated
Comment thread datafusion/physical-plan/src/display.rs
@asolimando
asolimando requested a review from kosiew July 21, 2026 04:17
Comment thread datafusion/physical-plan/src/statistics.rs Outdated
Comment thread docs/source/library-user-guide/upgrading/55.0.0.md
@asolimando
asolimando requested a review from xudong963 July 22, 2026 14:27
@alamb

alamb commented Jul 22, 2026

Copy link
Copy Markdown
Contributor

run benchmark sql_planner

@adriangbot

Copy link
Copy Markdown

🤖 Benchmark running (GKE) | trigger
Instance: c4a-highmem-16 (12 vCPU / 65 GiB) | Linux bench-c5051832006-1238-xtd2x 6.12.85+ #1 SMP Mon May 11 08:17:35 UTC 2026 aarch64 GNU/Linux

CPU Details (lscpu)
Architecture:                            aarch64
CPU op-mode(s):                          64-bit
Byte Order:                              Little Endian
CPU(s):                                  16
On-line CPU(s) list:                     0-15
Vendor ID:                               ARM
Model name:                              Neoverse-V2
Model:                                   1
Thread(s) per core:                      1
Core(s) per cluster:                     16
Socket(s):                               -
Cluster(s):                              1
Stepping:                                r0p1
BogoMIPS:                                2000.00
Flags:                                   fp asimd evtstrm aes pmull sha1 sha2 crc32 atomics fphp asimdhp cpuid asimdrdm jscvt fcma lrcpc dcpop sha3 sm3 sm4 asimddp sha512 sve asimdfhm dit uscat ilrcpc flagm sb paca pacg dcpodp sve2 sveaes svepmull svebitperm svesha3 svesm4 flagm2 frint svei8mm svebf16 i8mm bf16 dgh rng bti
L1d cache:                               1 MiB (16 instances)
L1i cache:                               1 MiB (16 instances)
L2 cache:                                32 MiB (16 instances)
L3 cache:                                80 MiB (1 instance)
NUMA node(s):                            1
NUMA node0 CPU(s):                       0-15
Vulnerability Gather data sampling:      Not affected
Vulnerability Indirect target selection: Not affected
Vulnerability Itlb multihit:             Not affected
Vulnerability L1tf:                      Not affected
Vulnerability Mds:                       Not affected
Vulnerability Meltdown:                  Not affected
Vulnerability Mmio stale data:           Not affected
Vulnerability Reg file data sampling:    Not affected
Vulnerability Retbleed:                  Not affected
Vulnerability Spec rstack overflow:      Not affected
Vulnerability Spec store bypass:         Mitigation; Speculative Store Bypass disabled via prctl
Vulnerability Spectre v1:                Mitigation; __user pointer sanitization
Vulnerability Spectre v2:                Mitigation; CSV2, BHB
Vulnerability Srbds:                     Not affected
Vulnerability Tsa:                       Not affected
Vulnerability Tsx async abort:           Not affected
Vulnerability Vmscape:                   Not affected

Comparing asolimando/statistics-registry-default (5f2b7f1) to 7f6cc60 (merge-base) diff using: sql_planner
Results will be posted here when complete


File an issue against this benchmark runner

@adriangbot

Copy link
Copy Markdown

🤖 Benchmark completed (GKE) | trigger

Instance: c4a-highmem-16 (12 vCPU / 65 GiB)

CPU Details (lscpu)
Architecture:                            aarch64
CPU op-mode(s):                          64-bit
Byte Order:                              Little Endian
CPU(s):                                  16
On-line CPU(s) list:                     0-15
Vendor ID:                               ARM
Model name:                              Neoverse-V2
Model:                                   1
Thread(s) per core:                      1
Core(s) per cluster:                     16
Socket(s):                               -
Cluster(s):                              1
Stepping:                                r0p1
BogoMIPS:                                2000.00
Flags:                                   fp asimd evtstrm aes pmull sha1 sha2 crc32 atomics fphp asimdhp cpuid asimdrdm jscvt fcma lrcpc dcpop sha3 sm3 sm4 asimddp sha512 sve asimdfhm dit uscat ilrcpc flagm sb paca pacg dcpodp sve2 sveaes svepmull svebitperm svesha3 svesm4 flagm2 frint svei8mm svebf16 i8mm bf16 dgh rng bti
L1d cache:                               1 MiB (16 instances)
L1i cache:                               1 MiB (16 instances)
L2 cache:                                32 MiB (16 instances)
L3 cache:                                80 MiB (1 instance)
NUMA node(s):                            1
NUMA node0 CPU(s):                       0-15
Vulnerability Gather data sampling:      Not affected
Vulnerability Indirect target selection: Not affected
Vulnerability Itlb multihit:             Not affected
Vulnerability L1tf:                      Not affected
Vulnerability Mds:                       Not affected
Vulnerability Meltdown:                  Not affected
Vulnerability Mmio stale data:           Not affected
Vulnerability Reg file data sampling:    Not affected
Vulnerability Retbleed:                  Not affected
Vulnerability Spec rstack overflow:      Not affected
Vulnerability Spec store bypass:         Mitigation; Speculative Store Bypass disabled via prctl
Vulnerability Spectre v1:                Mitigation; __user pointer sanitization
Vulnerability Spectre v2:                Mitigation; CSV2, BHB
Vulnerability Srbds:                     Not affected
Vulnerability Tsa:                       Not affected
Vulnerability Tsx async abort:           Not affected
Vulnerability Vmscape:                   Not affected
Details

group                                                 HEAD                                   asolimando_statistics-registry-default
-----                                                 ----                                   --------------------------------------
logical_aggregate_with_join                           1.03    467.4±1.54µs        ? ?/sec    1.00    453.9±1.14µs        ? ?/sec
logical_correlated_subquery_exists                    1.01    289.1±1.11µs        ? ?/sec    1.00    285.5±0.91µs        ? ?/sec
logical_correlated_subquery_in                        1.01    290.0±1.15µs        ? ?/sec    1.00    286.1±0.90µs        ? ?/sec
logical_distinct_many_columns                         1.00    573.5±1.35µs        ? ?/sec    1.00    574.6±1.83µs        ? ?/sec
logical_join_4_with_agg_and_filter                    1.03    258.8±2.78µs        ? ?/sec    1.00    250.2±0.85µs        ? ?/sec
logical_join_8_with_agg_sort_limit                    1.02    429.0±2.24µs        ? ?/sec    1.00    419.6±1.68µs        ? ?/sec
logical_join_chain_16                                 1.00    679.3±4.13µs        ? ?/sec    1.00    677.2±4.46µs        ? ?/sec
logical_join_chain_4                                  1.00    122.5±0.62µs        ? ?/sec    1.00    122.4±0.34µs        ? ?/sec
logical_join_chain_8                                  1.02    255.5±1.32µs        ? ?/sec    1.00    251.0±1.04µs        ? ?/sec
logical_multiple_subqueries                           1.02    528.7±2.32µs        ? ?/sec    1.00    520.3±2.35µs        ? ?/sec
logical_nested_cte_4_levels                           1.02    265.5±1.18µs        ? ?/sec    1.00    260.9±2.53µs        ? ?/sec
logical_plan_struct_join_agg_sort                     1.02    183.2±0.81µs        ? ?/sec    1.00    178.8±0.95µs        ? ?/sec
logical_plan_tpcds_all                                1.00     94.1±0.22ms        ? ?/sec    1.00     94.0±0.23ms        ? ?/sec
logical_plan_tpch_all                                 1.00      6.6±0.02ms        ? ?/sec    1.01      6.6±0.01ms        ? ?/sec
logical_scalar_subquery                               1.03    313.1±0.91µs        ? ?/sec    1.00    304.4±1.31µs        ? ?/sec
logical_select_all_from_1000                          1.00    104.6±0.36ms        ? ?/sec    1.00    105.0±0.67ms        ? ?/sec
logical_select_one_from_700                           1.02    332.3±2.17µs        ? ?/sec    1.00    326.5±2.19µs        ? ?/sec
logical_trivial_join_high_numbered_columns            1.02    292.0±0.92µs        ? ?/sec    1.00    287.5±1.21µs        ? ?/sec
logical_trivial_join_low_numbered_columns             1.01    278.8±1.07µs        ? ?/sec    1.00    274.8±1.43µs        ? ?/sec
logical_union_4_branches                              1.01    427.0±1.48µs        ? ?/sec    1.00    424.3±3.01µs        ? ?/sec
logical_union_8_branches                              1.02    822.9±3.40µs        ? ?/sec    1.00    810.1±3.93µs        ? ?/sec
logical_wide_aggregate_100_exprs                      1.00      4.5±0.01ms        ? ?/sec    1.01      4.6±0.01ms        ? ?/sec
logical_wide_case_50_exprs                            1.00      2.4±0.00ms        ? ?/sec    1.00      2.4±0.01ms        ? ?/sec
logical_wide_filter_200_predicates                    1.00   1330.9±4.59µs        ? ?/sec    1.00   1336.6±5.84µs        ? ?/sec
logical_wide_filter_50_predicates                     1.01    395.2±1.64µs        ? ?/sec    1.00    392.9±1.59µs        ? ?/sec
optimizer_correlated_exists                           1.02    252.9±0.80µs        ? ?/sec    1.00    247.9±0.77µs        ? ?/sec
optimizer_join_4_with_agg_filter                      1.00    444.8±2.03µs        ? ?/sec    1.03    459.0±1.94µs        ? ?/sec
optimizer_join_chain_4                                1.02    175.9±0.37µs        ? ?/sec    1.00    173.1±0.35µs        ? ?/sec
optimizer_join_chain_8                                1.01    555.8±1.48µs        ? ?/sec    1.00    549.3±1.18µs        ? ?/sec
optimizer_select_all_from_1000                        1.01      7.0±0.02ms        ? ?/sec    1.00      6.9±0.01ms        ? ?/sec
optimizer_select_one_from_700                         1.01    259.6±0.68µs        ? ?/sec    1.00    257.6±0.63µs        ? ?/sec
optimizer_tpcds_all                                   1.00    307.3±1.91ms        ? ?/sec    1.00    306.9±0.42ms        ? ?/sec
optimizer_tpch_all                                    1.00     16.9±0.06ms        ? ?/sec    1.00     16.9±0.03ms        ? ?/sec
optimizer_wide_aggregate_100                          1.00      2.3±0.01ms        ? ?/sec    1.00      2.3±0.00ms        ? ?/sec
optimizer_wide_filter_200                             1.00      3.8±0.01ms        ? ?/sec    1.00      3.8±0.01ms        ? ?/sec
physical_intersection                                 1.00    597.4±2.86µs        ? ?/sec    1.00    600.2±1.52µs        ? ?/sec
physical_join_consider_sort                           1.00   1056.1±3.89µs        ? ?/sec    1.01   1065.1±2.36µs        ? ?/sec
physical_join_distinct                                1.01    272.2±1.17µs        ? ?/sec    1.00    268.2±1.23µs        ? ?/sec
physical_many_self_joins                              1.01      7.8±0.02ms        ? ?/sec    1.00      7.7±0.02ms        ? ?/sec
physical_plan_clickbench_all                          1.00    127.1±0.32ms        ? ?/sec    1.01    127.7±0.41ms        ? ?/sec
physical_plan_clickbench_q1                           1.03   1403.5±8.79µs        ? ?/sec    1.00   1367.9±7.30µs        ? ?/sec
physical_plan_clickbench_q10                          1.00      2.1±0.01ms        ? ?/sec    1.01      2.1±0.01ms        ? ?/sec
physical_plan_clickbench_q11                          1.00      2.2±0.01ms        ? ?/sec    1.01      2.2±0.01ms        ? ?/sec
physical_plan_clickbench_q12                          1.00      2.3±0.01ms        ? ?/sec    1.00      2.3±0.01ms        ? ?/sec
physical_plan_clickbench_q13                          1.00      2.0±0.01ms        ? ?/sec    1.01      2.0±0.01ms        ? ?/sec
physical_plan_clickbench_q14                          1.00      2.2±0.01ms        ? ?/sec    1.01      2.2±0.01ms        ? ?/sec
physical_plan_clickbench_q15                          1.00      2.1±0.01ms        ? ?/sec    1.00      2.1±0.01ms        ? ?/sec
physical_plan_clickbench_q16                          1.00   1779.1±6.48µs        ? ?/sec    1.01   1800.5±7.78µs        ? ?/sec
physical_plan_clickbench_q17                          1.00   1824.9±6.17µs        ? ?/sec    1.01   1848.8±7.80µs        ? ?/sec
physical_plan_clickbench_q18                          1.00   1666.3±6.25µs        ? ?/sec    1.02   1691.6±7.07µs        ? ?/sec
physical_plan_clickbench_q19                          1.00      2.1±0.01ms        ? ?/sec    1.01      2.1±0.01ms        ? ?/sec
physical_plan_clickbench_q2                           1.03   1796.8±6.69µs        ? ?/sec    1.00   1748.0±6.65µs        ? ?/sec
physical_plan_clickbench_q20                          1.00   1521.7±7.45µs        ? ?/sec    1.02   1549.3±7.87µs        ? ?/sec
physical_plan_clickbench_q21                          1.00   1757.6±5.99µs        ? ?/sec    1.02   1792.0±7.19µs        ? ?/sec
physical_plan_clickbench_q22                          1.00      2.1±0.01ms        ? ?/sec    1.02      2.2±0.01ms        ? ?/sec
physical_plan_clickbench_q23                          1.00      2.3±0.01ms        ? ?/sec    1.01      2.4±0.02ms        ? ?/sec
physical_plan_clickbench_q24                          1.00      6.7±0.01ms        ? ?/sec    1.01      6.7±0.01ms        ? ?/sec
physical_plan_clickbench_q25                          1.00   1886.9±6.77µs        ? ?/sec    1.01   1911.6±6.07µs        ? ?/sec
physical_plan_clickbench_q26                          1.00  1723.4±11.81µs        ? ?/sec    1.01   1748.6±6.07µs        ? ?/sec
physical_plan_clickbench_q27                          1.00  1923.9±17.16µs        ? ?/sec    1.01   1938.7±8.58µs        ? ?/sec
physical_plan_clickbench_q28                          1.00      2.3±0.01ms        ? ?/sec    1.01      2.3±0.01ms        ? ?/sec
physical_plan_clickbench_q29                          1.00      2.5±0.01ms        ? ?/sec    1.01      2.5±0.01ms        ? ?/sec
physical_plan_clickbench_q3                           1.02   1687.6±7.33µs        ? ?/sec    1.00   1650.6±6.97µs        ? ?/sec
physical_plan_clickbench_q30                          1.00     15.4±0.03ms        ? ?/sec    1.00     15.5±0.05ms        ? ?/sec
physical_plan_clickbench_q31                          1.00      2.5±0.01ms        ? ?/sec    1.01      2.5±0.01ms        ? ?/sec
physical_plan_clickbench_q32                          1.00      2.5±0.01ms        ? ?/sec    1.00      2.5±0.01ms        ? ?/sec
physical_plan_clickbench_q33                          1.00      2.1±0.01ms        ? ?/sec    1.01      2.1±0.01ms        ? ?/sec
physical_plan_clickbench_q34                          1.00   1802.2±6.31µs        ? ?/sec    1.01   1814.5±6.13µs        ? ?/sec
physical_plan_clickbench_q35                          1.00   1845.0±6.79µs        ? ?/sec    1.00  1853.9±13.19µs        ? ?/sec
physical_plan_clickbench_q36                          1.02      2.2±0.02ms        ? ?/sec    1.00      2.1±0.01ms        ? ?/sec
physical_plan_clickbench_q37                          1.02      2.6±0.02ms        ? ?/sec    1.00      2.5±0.02ms        ? ?/sec
physical_plan_clickbench_q38                          1.02      2.6±0.01ms        ? ?/sec    1.00      2.5±0.02ms        ? ?/sec
physical_plan_clickbench_q39                          1.01      2.6±0.01ms        ? ?/sec    1.00      2.6±0.01ms        ? ?/sec
physical_plan_clickbench_q4                           1.02   1500.0±6.72µs        ? ?/sec    1.00   1468.1±5.76µs        ? ?/sec
physical_plan_clickbench_q40                          1.02      3.4±0.01ms        ? ?/sec    1.00      3.3±0.01ms        ? ?/sec
physical_plan_clickbench_q41                          1.00      2.9±0.01ms        ? ?/sec    1.00      2.9±0.01ms        ? ?/sec
physical_plan_clickbench_q42                          1.00      3.0±0.01ms        ? ?/sec    1.00      3.0±0.01ms        ? ?/sec
physical_plan_clickbench_q43                          1.01      3.2±0.01ms        ? ?/sec    1.00      3.2±0.01ms        ? ?/sec
physical_plan_clickbench_q44                          1.01   1581.1±6.49µs        ? ?/sec    1.00   1566.7±6.33µs        ? ?/sec
physical_plan_clickbench_q45                          1.01   1584.3±5.49µs        ? ?/sec    1.00   1561.7±6.96µs        ? ?/sec
physical_plan_clickbench_q46                          1.00   1891.6±6.14µs        ? ?/sec    1.00   1885.8±7.16µs        ? ?/sec
physical_plan_clickbench_q47                          1.00      2.6±0.01ms        ? ?/sec    1.00      2.6±0.01ms        ? ?/sec
physical_plan_clickbench_q48                          1.01      2.8±0.01ms        ? ?/sec    1.00      2.8±0.01ms        ? ?/sec
physical_plan_clickbench_q49                          1.01      2.8±0.01ms        ? ?/sec    1.00      2.8±0.01ms        ? ?/sec
physical_plan_clickbench_q5                           1.02   1635.6±6.43µs        ? ?/sec    1.00   1596.1±7.13µs        ? ?/sec
physical_plan_clickbench_q50                          1.01      2.7±0.02ms        ? ?/sec    1.00      2.7±0.01ms        ? ?/sec
physical_plan_clickbench_q51                          1.00      2.0±0.01ms        ? ?/sec    1.03      2.1±0.01ms        ? ?/sec
physical_plan_clickbench_q6                           1.00   1613.9±8.62µs        ? ?/sec    1.00   1607.9±6.74µs        ? ?/sec
physical_plan_clickbench_q7                           1.01   1433.2±6.02µs        ? ?/sec    1.00   1422.2±5.51µs        ? ?/sec
physical_plan_clickbench_q8                           1.01   1924.1±7.37µs        ? ?/sec    1.00   1898.2±6.85µs        ? ?/sec
physical_plan_clickbench_q9                           1.00   1914.5±6.45µs        ? ?/sec    1.01   1934.2±7.51µs        ? ?/sec
physical_plan_struct_join_agg_sort                    1.00   1305.2±4.73µs        ? ?/sec    1.01   1316.7±2.76µs        ? ?/sec
physical_plan_tpcds_all                               1.02    743.5±6.02ms        ? ?/sec    1.00    727.4±3.46ms        ? ?/sec
physical_plan_tpch_all                                1.03     46.4±0.12ms        ? ?/sec    1.00     45.3±0.09ms        ? ?/sec
physical_plan_tpch_q1                                 1.02   1559.4±7.89µs        ? ?/sec    1.00   1536.0±3.08µs        ? ?/sec
physical_plan_tpch_q10                                1.01      3.0±0.00ms        ? ?/sec    1.00      2.9±0.00ms        ? ?/sec
physical_plan_tpch_q11                                1.01      2.4±0.00ms        ? ?/sec    1.00      2.3±0.00ms        ? ?/sec
physical_plan_tpch_q12                                1.02   1283.2±2.15µs        ? ?/sec    1.00   1260.4±3.22µs        ? ?/sec
physical_plan_tpch_q13                                1.02   1075.7±2.52µs        ? ?/sec    1.00   1057.8±3.02µs        ? ?/sec
physical_plan_tpch_q14                                1.02   1433.4±3.99µs        ? ?/sec    1.00   1411.7±2.36µs        ? ?/sec
physical_plan_tpch_q16                                1.01   1683.3±3.09µs        ? ?/sec    1.00   1667.1±3.03µs        ? ?/sec
physical_plan_tpch_q17                                1.00   1707.7±2.76µs        ? ?/sec    1.00   1701.5±3.66µs        ? ?/sec
physical_plan_tpch_q18                                1.00   1985.6±2.83µs        ? ?/sec    1.00   1985.9±3.39µs        ? ?/sec
physical_plan_tpch_q19                                1.01   1907.7±4.29µs        ? ?/sec    1.00   1896.8±3.12µs        ? ?/sec
physical_plan_tpch_q2                                 1.01      3.7±0.02ms        ? ?/sec    1.00      3.7±0.01ms        ? ?/sec
physical_plan_tpch_q20                                1.02      2.2±0.00ms        ? ?/sec    1.00      2.2±0.00ms        ? ?/sec
physical_plan_tpch_q21                                1.01      3.0±0.00ms        ? ?/sec    1.00      3.0±0.00ms        ? ?/sec
physical_plan_tpch_q22                                1.02   1587.5±3.83µs        ? ?/sec    1.00   1555.0±4.44µs        ? ?/sec
physical_plan_tpch_q3                                 1.00  1918.8±10.54µs        ? ?/sec    1.00   1919.4±3.90µs        ? ?/sec
physical_plan_tpch_q4                                 1.01   1256.4±2.67µs        ? ?/sec    1.00   1240.3±4.35µs        ? ?/sec
physical_plan_tpch_q5                                 1.01      2.8±0.01ms        ? ?/sec    1.00      2.8±0.00ms        ? ?/sec
physical_plan_tpch_q6                                 1.01    665.2±1.82µs        ? ?/sec    1.00    655.6±2.12µs        ? ?/sec
physical_plan_tpch_q7                                 1.01      3.0±0.01ms        ? ?/sec    1.00      3.0±0.01ms        ? ?/sec
physical_plan_tpch_q8                                 1.02      4.0±0.02ms        ? ?/sec    1.00      4.0±0.00ms        ? ?/sec
physical_plan_tpch_q9                                 1.02      2.7±0.01ms        ? ?/sec    1.00      2.7±0.00ms        ? ?/sec
physical_select_aggregates_from_200                   1.00     15.6±0.03ms        ? ?/sec    1.00     15.7±0.06ms        ? ?/sec
physical_select_all_from_1000                         1.00    115.6±0.16ms        ? ?/sec    1.00    116.0±0.43ms        ? ?/sec
physical_select_one_from_700                          1.00    779.7±5.30µs        ? ?/sec    1.00    783.0±4.14µs        ? ?/sec
physical_sorted_union_order_by_10_int64               1.01      4.3±0.01ms        ? ?/sec    1.00      4.3±0.00ms        ? ?/sec
physical_sorted_union_order_by_10_uint64              1.00      8.5±0.05ms        ? ?/sec    1.00      8.4±0.01ms        ? ?/sec
physical_sorted_union_order_by_50_int64               1.01    107.1±0.59ms        ? ?/sec    1.00    105.9±0.30ms        ? ?/sec
physical_sorted_union_order_by_50_uint64              1.01    366.6±2.85ms        ? ?/sec    1.00    363.6±0.69ms        ? ?/sec
physical_theta_join_consider_sort                     1.00   1087.6±9.00µs        ? ?/sec    1.00   1088.5±3.17µs        ? ?/sec
physical_unnest_to_join                               1.00    663.6±1.78µs        ? ?/sec    1.00    664.3±2.01µs        ? ?/sec
physical_window_function_partition_by_12_on_values    1.00    719.6±1.68µs        ? ?/sec    1.00    720.2±1.47µs        ? ?/sec
physical_window_function_partition_by_30_on_values    1.00   1423.5±1.91µs        ? ?/sec    1.00   1427.0±2.04µs        ? ?/sec
physical_window_function_partition_by_4_on_values     1.00    442.6±1.26µs        ? ?/sec    1.00    444.5±1.72µs        ? ?/sec
physical_window_function_partition_by_7_on_values     1.00    543.7±1.57µs        ? ?/sec    1.00    544.5±1.52µs        ? ?/sec
physical_window_function_partition_by_8_on_values     1.00    582.7±2.47µs        ? ?/sec    1.00    584.2±1.53µs        ? ?/sec
with_param_values_many_columns                        1.00    433.4±2.62µs        ? ?/sec    1.01    435.8±2.62µs        ? ?/sec

Resource Usage

sql_planner — base (merge-base)

Metric Value
Wall time 2560.6s
Peak memory 131.1 MiB
Avg memory 62.3 MiB
CPU user 1883.9s
CPU sys 1.3s
Peak spill 0 B

sql_planner — branch

Metric Value
Wall time 2525.6s
Peak memory 129.6 MiB
Avg memory 62.0 MiB
CPU user 1876.8s
CPU sys 1.3s
Peak spill 0 B

File an issue against this benchmark runner

@kosiew kosiew left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

@asolimando
Thanks for the iteration. The provider-specific child statistics work is heading in the right direction, but there is still one behavior issue that should be addressed before merging. I also noticed a small documentation mismatch.

Comment thread datafusion/physical-plan/src/statistics.rs Outdated
Comment thread datafusion/physical-plan/src/operator_statistics/mod.rs Outdated
@asolimando
asolimando force-pushed the asolimando/statistics-registry-default branch from 26095c7 to b2548db Compare July 27, 2026 16:18
@asolimando
asolimando requested a review from kosiew July 27, 2026 18:24

@kosiew kosiew left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

@asolimando
Thanks for iteration.
I found one remaining issue around provider delegation. A provider that does not handle the current node can still trigger child statistics computation before a later provider or the operator fallback gets a chance to run. This can introduce unexpected work or surface child errors that should have been avoided.

Comment thread datafusion/physical-plan/src/statistics.rs Outdated

@kosiew kosiew left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

@asolimando
Thanks for continuing to refine the provider statistics flow. The explicit matches() hook improves the new provider path, but there is still a compatibility issue for existing providers that rely on returning Delegate from compute_statistics. I think this needs one more change.

Comment thread datafusion/physical-plan/src/statistics.rs

@kosiew kosiew left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

@asolimando
Thanks for the follow-up. I think the overall direction looks good and the rationale for preserving eager child resolution makes sense. The EXPLAIN/ANALYZE registry propagation, display deduplication, constructor cleanup, contract restoration, and the new regression test all address the earlier feedback.

I do think there is one remaining issue before this is ready. The current child resolution error handling is now too broad and can end up masking provider bugs by treating every failure as skippable.

Comment thread datafusion/physical-plan/src/statistics.rs
@asolimando
asolimando requested a review from kosiew July 31, 2026 07:54

@kosiew kosiew left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

@asolimando

Thanks for iteration and your persistence.

Looks 👍 to me

@asolimando

Copy link
Copy Markdown
Member Author

Hey @xudong963, you seem happy with the modifications you required earlier, but I still see the "request changes" status. Is there anything missing you have already identified, or do you just want to take another look?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

auto detected api change Auto detected API change common Related to common crate core Core DataFusion crate documentation Improvements or additions to documentation optimizer Optimizer rules physical-plan Changes to the physical-plan crate sqllogictest SQL Logic Tests (.slt)

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Pluggable operator-level statistics propagation (StatisticsRegistry)

6 participants