mz_adapter/optimize/view.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//! An Optimizer that
11//! 1. Optimistically calls `optimize_mir_constant`.
12//! 2. Then, if we haven't arrived at a constant, it calls `optimize_mir_local`, i.e., the
13//! logical optimizer.
14//!
15//! This is used for `CREATE VIEW` statements and in various other situations where no physical
16//! optimization is needed, such as for `INSERT` statements.
17
18use std::time::Instant;
19
20use mz_expr::OptimizedMirRelationExpr;
21use mz_sql::optimizer_metrics::OptimizerMetrics;
22use mz_sql::plan::HirRelationExpr;
23use mz_transform::TransformCtx;
24use mz_transform::dataflow::DataflowMetainfo;
25use mz_transform::typecheck::{SharedContext as TypecheckContext, empty_context};
26
27use crate::optimize::{
28 Optimize, OptimizerConfig, OptimizerError, optimize_mir_constant, optimize_mir_local,
29 trace_plan,
30};
31
32pub struct Optimizer {
33 /// A typechecking context to use throughout the optimizer pipeline.
34 typecheck_ctx: TypecheckContext,
35 /// Optimizer config.
36 config: OptimizerConfig,
37 /// Optimizer metrics.
38 ///
39 /// Allowed to be `None` for cases where view optimization is invoked outside of the
40 /// coordinator context and the metrics are not available.
41 metrics: Option<OptimizerMetrics>,
42}
43
44impl Optimizer {
45 pub fn new(config: OptimizerConfig, metrics: Option<OptimizerMetrics>) -> Self {
46 Self {
47 typecheck_ctx: empty_context(),
48 config,
49 metrics,
50 }
51 }
52}
53
54impl Optimize<HirRelationExpr> for Optimizer {
55 type To = OptimizedMirRelationExpr;
56
57 fn optimize(&mut self, expr: HirRelationExpr) -> Result<Self::To, OptimizerError> {
58 let time = Instant::now();
59
60 // Trace the pipeline input under `optimize/raw`.
61 trace_plan!(at: "raw", &expr);
62
63 // HIR ⇒ MIR lowering and decorrelation
64 let mut expr = expr.lower(&self.config, self.metrics.as_ref())?;
65
66 let mut df_meta = DataflowMetainfo::default();
67 let mut transform_ctx = TransformCtx::local(
68 &self.config.features,
69 &self.typecheck_ctx,
70 &mut df_meta,
71 self.metrics.as_ref(),
72 );
73
74 // First, we run a very simple optimizer pipeline, which only folds constants. This takes
75 // care of constant INSERTs. (This optimizer is also used for INSERTs, not just VIEWs.)
76 expr = optimize_mir_constant(expr, &mut transform_ctx)?;
77
78 // MIR ⇒ MIR optimization (local)
79 let expr = if expr.as_const().is_some() {
80 // No need to optimize further, because we already have a constant.
81 // But trace this at "local", so that `EXPLAIN LOCALLY OPTIMIZED PLAN` can pick it up.
82 trace_plan!(at: "local", &expr);
83 OptimizedMirRelationExpr(expr)
84 } else {
85 // Call the real optimization.
86 optimize_mir_local(expr, &mut transform_ctx)?
87 };
88
89 if let Some(metrics) = &self.metrics {
90 metrics.observe_e2e_optimization_time("view", time.elapsed());
91 }
92
93 // Return the resulting OptimizedMirRelationExpr.
94 Ok(expr)
95 }
96}