Skip to main content

mz_adapter/
explain.rs

1// Copyright Materialize, Inc. and contributors. All rights reserved.
2//
3// Use of this software is governed by the Business Source License
4// included in the LICENSE file.
5//
6// As of the Change Date specified in that file, in accordance with
7// the Business Source License, use of this software will be governed
8// by the Apache License, Version 2.0.
9
10//! `EXPLAIN` support for various intermediate representations.
11//!
12//! Ideally, the `EXPLAIN` support for each IR should be in the crate where this
13//! IR is defined. However, we need to resort to an [`Explainable`] newtype
14//! struct in order to provide alternate [`mz_repr::explain::Explain`]
15//! implementations for some structs (see the [`mir`]) module for details.
16
17use std::collections::BTreeMap;
18use std::sync::Arc;
19
20use mz_compute_types::dataflows::DataflowDescription;
21use mz_expr::explain::ExplainContext;
22use mz_repr::GlobalId;
23use mz_repr::explain::{Explain, ExplainConfig, ExplainError, ExplainFormat, ExprHumanizer};
24use mz_repr::optimize::OptimizerFeatures;
25use mz_transform::dataflow::DataflowMetainfo;
26use mz_transform::notice::OptimizerNotice;
27
28use crate::AdapterError;
29
30pub(crate) mod fast_path;
31pub(crate) mod hir;
32pub(crate) mod insights;
33pub(crate) mod lir;
34pub(crate) mod mir;
35pub(crate) mod optimizer_trace;
36
37/// Newtype struct for wrapping types that should
38/// implement the [`mz_repr::explain::Explain`] trait.
39pub(crate) struct Explainable<'a, T>(&'a mut T);
40
41impl<'a, T> Explainable<'a, T> {
42    pub(crate) fn new(t: &'a mut T) -> Explainable<'a, T> {
43        Explainable(t)
44    }
45}
46
47/// Convenience method to derive an `ExplainContext` from the `index_imports` in
48/// the given `plan` and all other input parameters, wrap the `plan` in an
49/// `Explainable`, and finally compute and return the `explain(...)` result.
50pub(crate) fn explain_dataflow<T, O>(
51    mut plan: DataflowDescription<T, (), O>,
52    format: ExplainFormat,
53    config: &ExplainConfig,
54    features: &OptimizerFeatures,
55    humanizer: &dyn ExprHumanizer,
56    cardinality_stats: BTreeMap<GlobalId, usize>,
57    target_cluster: Option<&str>,
58    dataflow_metainfo: &DataflowMetainfo<Arc<OptimizerNotice>>,
59) -> Result<String, AdapterError>
60where
61    for<'a> Explainable<'a, DataflowDescription<T, (), O>>:
62        Explain<'a, Context = ExplainContext<'a>>,
63{
64    // Collect the list of indexes used by the dataflow at this point.
65    let used_indexes = dataflow_metainfo.used_indexes(&plan);
66
67    let optimizer_notices = OptimizerNotice::explain(
68        &dataflow_metainfo.optimizer_notices,
69        humanizer,
70        config.redacted,
71    )
72    .map_err(ExplainError::FormatError)?;
73
74    let context = ExplainContext {
75        config,
76        features,
77        humanizer,
78        cardinality_stats,
79        used_indexes,
80        finishing: Default::default(),
81        duration: Default::default(),
82        target_cluster,
83        optimizer_notices,
84    };
85
86    Ok(Explainable::new(&mut plan).explain(&format, &context)?)
87}
88
89/// Convenience method to explain a single plan.
90///
91/// In the long term, this method and [`explain_dataflow`] should be unified. In
92/// order to do that, however, we first need to generalize the role
93/// [`DataflowMetainfo`] as a carrier of metainformation for the optimization
94/// pass in general, and not for a specific structure representing an
95/// intermediate result.
96pub(crate) fn explain_plan<T>(
97    mut plan: T,
98    format: ExplainFormat,
99    config: &ExplainConfig,
100    features: &OptimizerFeatures,
101    humanizer: &dyn ExprHumanizer,
102    cardinality_stats: BTreeMap<GlobalId, usize>,
103    target_cluster: Option<&str>,
104) -> Result<String, AdapterError>
105where
106    for<'a> Explainable<'a, T>: Explain<'a, Context = ExplainContext<'a>>,
107{
108    let context = ExplainContext {
109        config,
110        features,
111        humanizer,
112        cardinality_stats,
113        used_indexes: Default::default(),
114        finishing: Default::default(),
115        duration: Default::default(),
116        target_cluster,
117        optimizer_notices: Default::default(),
118    };
119
120    Ok(Explainable::new(&mut plan).explain(&format, &context)?)
121}