Skip to content

Commit a739581

Browse files
committed
Create a special optimizer pipeline for constant INSERTs
1 parent 3492bed commit a739581

File tree

4 files changed

+67
-3
lines changed

4 files changed

+67
-3
lines changed

src/adapter/src/coord/sequencer/inner.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2647,6 +2647,7 @@ impl Coordinator {
26472647
// Collect optimizer parameters.
26482648
let optimizer_config = optimize::OptimizerConfig::from(self.catalog().system_config());
26492649

2650+
// (`optimize::view::Optimizer` has a special case for INSERTs.)
26502651
let mut optimizer = optimize::view::Optimizer::new(optimizer_config, None);
26512652

26522653
// HIR ⇒ MIR lowering and MIR ⇒ MIR optimization (local)

src/adapter/src/optimize.rs

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -359,6 +359,23 @@ fn optimize_mir_local(
359359
Ok::<_, OptimizerError>(expr)
360360
}
361361

362+
/// This calls a simple optimizer that is able to fully optimize constant INSERTs. For more details,
363+
/// see `mz_transform::Optimizer::constant_insert_optimizer`.
364+
#[mz_ore::instrument(target = "optimizer", level = "debug", name = "constant_insert")]
365+
fn optimize_mir_constant_insert(
366+
expr: MirRelationExpr,
367+
ctx: &mut TransformCtx,
368+
) -> Result<MirRelationExpr, OptimizerError> {
369+
#[allow(deprecated)]
370+
let optimizer = mz_transform::Optimizer::constant_insert_optimizer(ctx);
371+
let expr = optimizer.optimize(expr, ctx)?;
372+
373+
// Trace the result of this phase.
374+
mz_repr::explain::trace_plan(expr.as_inner());
375+
376+
Ok::<_, OptimizerError>(expr.0)
377+
}
378+
362379
macro_rules! trace_plan {
363380
(at: $span:literal, $plan:expr) => {
364381
tracing::debug_span!(target: "optimizer", $span).in_scope(|| {

src/adapter/src/optimize/view.rs

Lines changed: 16 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,10 @@ use mz_transform::dataflow::DataflowMetainfo;
1919
use mz_transform::typecheck::{empty_context, SharedContext as TypecheckContext};
2020
use mz_transform::TransformCtx;
2121

22-
use crate::optimize::{optimize_mir_local, trace_plan, Optimize, OptimizerConfig, OptimizerError};
22+
use crate::optimize::{
23+
optimize_mir_constant_insert, optimize_mir_local, trace_plan, Optimize, OptimizerConfig,
24+
OptimizerError,
25+
};
2326

2427
pub struct Optimizer {
2528
/// A typechecking context to use throughout the optimizer pipeline.
@@ -53,14 +56,24 @@ impl Optimize<HirRelationExpr> for Optimizer {
5356
trace_plan!(at: "raw", &expr);
5457

5558
// HIR ⇒ MIR lowering and decorrelation
56-
let expr = expr.lower(&self.config, self.metrics.as_ref())?;
59+
let mut expr = expr.lower(&self.config, self.metrics.as_ref())?;
5760

5861
let mut df_meta = DataflowMetainfo::default();
5962
let mut transform_ctx =
6063
TransformCtx::local(&self.config.features, &self.typecheck_ctx, &mut df_meta);
6164

65+
// This optimizer is also used for INSERTs (in addition to VIEWs). Therefore, we first call
66+
// a very simple optimizer, which should fully take care of constant INSERTs.
67+
expr = optimize_mir_constant_insert(expr, &mut transform_ctx)?;
68+
6269
// MIR ⇒ MIR optimization (local)
63-
let expr = optimize_mir_local(expr, &mut transform_ctx)?;
70+
let expr = if expr.as_const().is_some() {
71+
// No need to optimize further, because we already have a constant.
72+
OptimizedMirRelationExpr(expr)
73+
} else {
74+
// Call the real optimization.
75+
optimize_mir_local(expr, &mut transform_ctx)?
76+
};
6477

6578
if let Some(metrics) = &self.metrics {
6679
metrics.observe_e2e_optimization_time("view", time.elapsed());

src/transform/src/lib.rs

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -819,6 +819,39 @@ impl Optimizer {
819819
}
820820
}
821821

822+
/// Builds a tiny optimizer, which is only suitable for optimizing constant inserts, e.g.
823+
/// ```code
824+
/// Return
825+
/// FlatMap wrap2(1, 2)
826+
/// Get l0
827+
/// With
828+
/// cte l0 =
829+
/// Constant
830+
/// - ()
831+
/// ```
832+
/// which is planned for stuff like `INSERT INTO t VALUES (1,2);`.
833+
///
834+
/// The important thing here is dealing with the `wrap` table function, which is always planned
835+
/// for `VALUES`, and results in a Let binding in MIR. This is why we need to call
836+
/// `NormalizeLets`, so that this Let binding is inlined. Then, `FoldConstants` is able to
837+
/// evaluate the table function.
838+
///
839+
/// The `InsertMultiRow` test is meant to make noise if this doesn't actually reach a constant
840+
/// for a constant INSERT.
841+
pub fn constant_insert_optimizer(_ctx: &mut TransformCtx) -> Self {
842+
let transforms: Vec<Box<dyn Transform>> = vec![
843+
Box::new(NormalizeLets::new(false)),
844+
Box::new(canonicalization::ReduceScalars),
845+
Box::new(FoldConstants {
846+
limit: Some(FOLD_CONSTANTS_LIMIT),
847+
}),
848+
];
849+
Self {
850+
name: "constant_insert_optimizer",
851+
transforms,
852+
}
853+
}
854+
822855
/// Optimizes the supplied relation expression.
823856
///
824857
/// These optimizations are performed with no information about available arrangements,

0 commit comments

Comments
 (0)