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>(
51    mut plan: DataflowDescription<T>,
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>>: Explain<'a, Context = ExplainContext<'a>>,
62{
63    // Collect the list of indexes used by the dataflow at this point.
64    let used_indexes = dataflow_metainfo.used_indexes(&plan);
65
66    let optimizer_notices = OptimizerNotice::explain(
67        &dataflow_metainfo.optimizer_notices,
68        humanizer,
69        config.redacted,
70    )
71    .map_err(ExplainError::FormatError)?;
72
73    let context = ExplainContext {
74        config,
75        features,
76        humanizer,
77        cardinality_stats,
78        used_indexes,
79        finishing: Default::default(),
80        duration: Default::default(),
81        target_cluster,
82        optimizer_notices,
83    };
84
85    Ok(Explainable::new(&mut plan).explain(&format, &context)?)
86}
87
88/// Convenience method to explain a single plan.
89///
90/// In the long term, this method and [`explain_dataflow`] should be unified. In
91/// order to do that, however, we first need to generalize the role
92/// [`DataflowMetainfo`] as a carrier of metainformation for the optimization
93/// pass in general, and not for a specific structure representing an
94/// intermediate result.
95pub(crate) fn explain_plan<T>(
96    mut plan: T,
97    format: ExplainFormat,
98    config: &ExplainConfig,
99    features: &OptimizerFeatures,
100    humanizer: &dyn ExprHumanizer,
101    cardinality_stats: BTreeMap<GlobalId, usize>,
102    target_cluster: Option<&str>,
103) -> Result<String, AdapterError>
104where
105    for<'a> Explainable<'a, T>: Explain<'a, Context = ExplainContext<'a>>,
106{
107    let context = ExplainContext {
108        config,
109        features,
110        humanizer,
111        cardinality_stats,
112        used_indexes: Default::default(),
113        finishing: Default::default(),
114        duration: Default::default(),
115        target_cluster,
116        optimizer_notices: Default::default(),
117    };
118
119    Ok(Explainable::new(&mut plan).explain(&format, &context)?)
120}