asolimando commented on code in PR #23651:
URL: https://github.com/apache/datafusion/pull/23651#discussion_r3665430333


##########
datafusion/physical-plan/src/statistics.rs:
##########
@@ -182,35 +253,230 @@ impl StatisticsContext {
             requests.len(),
             children.len()
         );
-        let child_stats = children
+        children
             .iter()
             .zip(requests)
             .map(|(child, directive)| match directive {
-                ChildStats::At(p) => {
-                    self.compute(child.as_ref(), 
&StatisticsArgs::new().with_partition(p))
-                }
+                ChildStats::At(p) => self.compute_base(
+                    child.as_ref(),
+                    &StatisticsArgs::new().with_partition(*p),
+                ),
                 ChildStats::Skip => {
                     
Ok(Arc::new(Statistics::new_unknown(child.schema().as_ref())))
                 }
             })
-            .collect::<Result<Vec<_>>>()?;
+            .collect()
+    }
+
+    /// Runs the provider chain, returning the first `Computed` result's core
+    /// statistics (and recording its extensions), or `None` if the chain is 
empty
+    /// or all delegate. A partition-blind provider applies only to overall 
stats
+    /// (its default `compute_statistics_with_args` delegates per partition).
+    ///
+    /// Each provider's child statistics come from its own
+    /// 
[`child_stats_requests`](crate::operator_statistics::StatisticsProvider::child_stats_requests)
+    /// and are memoized, so a walk with no providers pays nothing.
+    fn try_provider_stats(
+        &self,
+        plan: &dyn ExecutionPlan,
+        children: &[&Arc<dyn ExecutionPlan>],
+        args: &StatisticsArgs,
+    ) -> Result<Option<Arc<Statistics>>> {
+        let providers = self.registry.providers();
+        if providers.is_empty() {
+            return Ok(None);
+        }
+        let partition = args.partition();
+        for provider in providers {
+            let requests = provider.child_stats_requests(plan, partition);
+            let child_statistics = self.resolve_children(plan, children, 
&requests)?;

Review Comment:
   Thanks for the suggestion, I have implemented it and it doesn't only make 
performance better, it also allowed to move those "guards" into a dedicated 
place, while before they had to live in `compute`, now there is a better 
separation of concerns and better overall readability!
   
   I have added in `83b5e8f2c` a `matches(&self, plan) -> bool` guard to 
`StatisticsProvider` (default to `true`), which is checked in 
`try_provider_stats`, only providers returning `true` are invoked and they 
don't resolve children statistics unnecessarily. There was a name clash on 
`supports` so I went for `matches`, we can revisit this if needed.
   
   I have taken advantage of this new capability and I have migrated existing 
providers, tests and examples (code looks cleaner), and I have added 
`test_non_matching_provider_does_not_trigger_child_walk` to cover providers, 
which is analogous to the previous `test_provider_opts_out_of_child_stats`, 
which was covering providers vs built-in.



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: [email protected]

For queries about this service, please contact Infrastructure at:
[email protected]


---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to