Skip to content

Physical properties: replace Materialization with timing × lifetime (None / OneEvaluation / AcrossEvaluations) and a schedule for shareable results, with r^phys and α^phys #1200

Open

Description

@zzylol

Example

sum_over_time(http_requests_total[1h]), exact, every 10 s, over a tumbling-window chain of 10 s windows. Consecutive evaluations share 359 of their 360 windows. There are three ways to run the chain:

Plan What happens between evaluations $(\tau, \ell)$ Today's Materialization
Rebuild every time nothing is kept; each evaluation builds all 360 windows (QueryTime, None) NotMaterialized
Keep the chain at query time each evaluation builds the newest window and keeps the rest for the next one (QueryTime, AcrossEvaluations(Memory)) MatAtQueryKeptAcrossEvaluations(Memory)
Build the chain at ingestion windows are built as data arrives; evaluations only merge (IngestionTime, AcrossEvaluations(Memory)) MatAtIngestion(Memory)

Today one enum value, Materialization, encodes both when a node runs and how long its output lives. MatAtQueryKeptAcrossEvaluations mixes the two, and timing is stored a second time next to it.

Representation, rules, enumeration

  • (a) Representation. Each physical candidate stores $p^{\mathrm{phys}} = (\tau, \ell)$:

    • timing;
    • lifetime None / OneEvaluation(medium) / AcrossEvaluations(medium).

    The invalid combination cannot be constructed (PhysicalProperties::new). Materialization is deleted.

  • (b) Rules. No logical rules change. Stage 2's expansion step creates, for each logical candidate, one physical candidate per valid (timing, lifetime) pair. There is no schedule dimension (decided 2026-11-06).

  • (c) Enumeration.

    • Stage 3 picks among these alternatives.
    • $\alpha^{\mathrm{phys}}$ restricts which producers a consumer input may pick: it is a function of the consumer's own $p^{\mathrm{phys}}_c$ (timing and lifetime). Stage 3 checks alignment per context (below).

Formulation

A candidate's physical properties are $p_v^{\mathrm{phys}} = (\tau_v, \ell_v)$, exactly the paper's. There is no schedule property (decided 2026-11-06):

$$\tau_v \in {\mathrm{IngestionTime}, \mathrm{QueryTime}}, \qquad \ell_v \in {\mathrm{None}, \mathrm{OneEvaluation}, \mathrm{AcrossEvaluations}}.$$

  • $\ell = \mathrm{None}$: the output is discarded after its consumer's execution completes.
  • $\ell = \mathrm{OneEvaluation}$: kept until all consumers within one evaluation finish.
  • $\ell = \mathrm{AcrossEvaluations}$: kept throughout the evaluation period, so later evaluations reuse it.
  • $\text{materialized}(v) \iff \ell_v \ne \mathrm{None}$, derived, not stored.
  • $r^{\mathrm{phys}}_{c,i}$ is not stored: it is a function of the consumer's own $p^{\mathrm{phys}}c$ (decided 2026-11-05). $\alpha^{\mathrm{phys}}{u,c,i}$ = producer_satisfies_physical_requirements$(u, c)$ takes the two candidates, not bare properties, and checks timing and lifetime:
Consumer $\tau_c$ Producer $(\tau_u, \ell_u)$ that is OK Not OK
QueryTime (QT, None), (QT, OneEval), (QT, AcrossEval), (IT, AcrossEval) (IT, None): an unmaterialized ingestion-time output is gone by query time
IngestionTime (IT, None), (IT, AcrossEval) every query-time producer

Reusing an earlier evaluation's work is the producer's $\ell$, a cost choice, not a requirement, so there is no "later evaluation" row.

  • Cost: $w_v$ adds $C^{\text{one}}{\text{retain}}(v)$ for OneEvaluation and $C^{\text{across}}{\text{retain}}(v)$ for AcrossEvaluations.

No schedule property (decided 2026-11-06; replaces the 2026-11-04 schedule $\sigma_v$). When a result can be read follows from its lifetime and window layout $\omega_v$:

$(\tau, \ell)$ Consumer $c$, in context $\kappa$, may read it iff Example
(·, None) same execution context as $c$: $\kappa_q$, $I_r$ or $\kappa_m$ (#1204) —
(QueryTime, OneEvaluation) the result belongs to $\kappa$ A and B both every 10 s at phase 0, evaluated together: one result in their context
(·, AcrossEvaluations), tumbling-window width $w$ $w$ divides every evaluation time of $\kappa$: the evaluation grid $\gcd(\text{interval}, \text{step}, \text{phase})$ of FixedIntervalAt, every Scheduled time, or a OneTime query's time; never for FixedInterval without a phase, OneTime without a time, EstimatedRate or Unknown two 10 s queries at phases 0 s and 5 s: both read one chain with $w = 5$ s

Invalid combination of $(\tau, \ell)$. PhysicalProperties::new rejects exactly one:

# Combination Why invalid
1 $\tau$ = IngestionTime, $\ell$ = OneEvaluation there is no evaluation at ingestion time

Valid pairs, and how Stage 3 runs each:

$\tau$ $\ell$ Today's name Materialized How Stage 3 runs it
query None NotMaterialized no once in each context that selects it
query OneEvaluation MatAtQuery yes once in each context that selects it; the consumers of that evaluation share it; held until its slowest consumer in the evaluation finishes ($H[m]$)
query AcrossEvaluations MatAtQueryKeptAcrossEvaluations yes once; the next evaluation reuses it; charged by the tumbling windows kept ($S[m]$ or $\pi[m,\ell]$)
ingestion None NotMaterialized at ingestion time no once per second of data in $I_r$, shared by the consumers of one refresh window
ingestion AcrossEvaluations MatAtIngestion yes maintained continuously; standing cost
ingestion OneEvaluation — invalid there is no evaluation at ingestion time

Data structures and interfaces per stage

Types (crates/types/src/physical/):

pub enum ExecutionTiming { IngestionTime, QueryTime }            // exists

/// ℓ_v. Only a materialized result has a medium.
pub enum Lifetime { None, OneEvaluation(StorageMedium), AcrossEvaluations(StorageMedium) }

/// p_v^phys = (τ, ℓ). `new` rejects only (IngestionTime, OneEvaluation).
pub struct PhysicalProperties { timing: ExecutionTiming, lifetime: Lifetime }
impl PhysicalProperties {
    pub fn new(timing: ExecutionTiming, lifetime: Lifetime) -> Result<Self, PhysicalPropertiesError>;
    pub fn timing(&self) -> ExecutionTiming;
    pub fn lifetime(&self) -> Lifetime;
    pub fn is_materialized(&self) -> bool;                       // ℓ ≠ None
}

impl PhysicalCandidate {
    /// Whether a consumer running in `context` can read this producer (the alignment
    /// table above): for a windowed AcrossEvaluations producer, w (read from its logical
    /// window layout ω_v) divides every evaluation time of the context; true for ℓ = None,
    /// and for OneEvaluation in the same context.
    pub fn delivers_on(&self, memo: &Memo, context: &ExecutionContext) -> bool;
}

/// α^phys_{u,c,i} = r^phys_{c,i} as a function of the consumer's own p^phys_c
/// (no PhysicalRequirement struct): timing and lifetime only (table above).
/// Stage 3 checks `delivers_on(κ)` per context (#1204).
pub fn producer_satisfies_physical_requirements(producer: &PhysicalCandidate, consumer: &PhysicalCandidate) -> bool;

Stage 1: no change. Pass 1 and Pass 2 produce logical candidates without physical properties.

Stage 2 (physical-asap-optimization):

  • PhysicalCandidate { timing, materialization } becomes PhysicalCandidate { logical_candidate_id: CandidateForMemoGroupId, physical_properties: PhysicalProperties }; likewise PhysicalCandidateKey.
  • Candidate generation enumerates valid $(\tau, \ell)$ pairs.
  • compatible_timing becomes producer_satisfies_physical_requirements(producer, consumer); there is no per-input requirement to store. PhysicalCandidate has no input_requirements.
  • may_keep_across_evaluations_per_sole_reader_query (memo_candidates.rs:85) reads Lifetime::AcrossEvaluations.

Stage 3 (plan-selection): run_kind (groups.rs:346) takes PhysicalProperties:

$$\text{RunKind}(v) = \begin{cases} \text{PerContext} & \tau = \text{query},\ \ell \in {\text{None}, \text{OneEvaluation}} \ \text{Ingestion} & \tau = \text{ingestion},\ \ell = \text{None} \ \text{Materialized} & \ell = \text{AcrossEvaluations} \end{cases}$$

OneEvaluation moves to PerContext (one result per evaluation context); the other branches match today's.

Stage 3: a OneEvaluation candidate's rate is its context's $\rho_\kappa$, not a schedule-group choice. The MILP side, contexts for (QueryTime, None) and (QueryTime, OneEvaluation) candidates, is #1204.

Cost (asap-cost): matches on Lifetime for the retention terms, and prices a OneEvaluation candidate at its context's rate $\rho_\kappa$.

Export (crates/types/src/ir/physical_export.rs): writes timing and lifetime. Either the backend's wire format keeps materialization, mapped at export, or it changes together with the backend.

Current vs proposed

Notation Today Proposed
$\tau_v$ PhysicalCandidate::timing and also implied by Materialization::timing() (materialization.rs:40) for three of four values PhysicalProperties::timing, stored once
$\ell_v$ folded into Materialization (materialization.rs:21): NotMaterialized, MatAtQuery, MatAtQueryKeptAcrossEvaluations, MatAtIngestion Lifetime::{None, OneEvaluation, AcrossEvaluations}
medium payload of the three materialized values payload of OneEvaluation / AcrossEvaluations
materialized Materialization::is_materialized_view PhysicalProperties::is_materialized (derived)
invalid pairs not representable, since each value fixes both rejected by PhysicalProperties::new
$r^{\mathrm{phys}}_{c,i}$ the consumer's timing, passed to compatible_timing a function of the consumer's own PhysicalProperties; no requirement struct
$\alpha^{\mathrm{phys}}$ compatible_timing (configurations.rs:394): same timing, or query-time consumer of MatAtIngestion producer_satisfies_physical_requirements
run kind run_kind(timing, materialization) run_kind(PhysicalProperties)
schedule of a materialized result chosen in the MILP (schedule groups z[m, G], #1095); one materialized-chain candidate whatever the phases of the queries reaching it no property: OneEvaluation runs on its context's schedule; grids are anchored at phase 0
query on a different phase IncompatibleOutputs reader constraint delivers_on per context: $w$ divides every evaluation time; the gcd closure of ranges, steps and phases offers a width both can read
how much is retained Stage 3 ($S[m]$, $\pi[m,\ell]$, #1095's constraint 10) unchanged: a Stage 3 decision, not a property

How much is retained stays a Stage 3 decision. The number of tumbling windows an AcrossEvaluations chain keeps depends on the longest range among the queries reading it. The MILP already chooses it. Making it a property would copy each candidate once per retention amount, the redundancy #1199 describes.

Alternative considered: drop query-time retention. Reuse across evaluations would then come only from ingestion-time chains. Rejected:

  • a deployment without ingestion pipelines could no longer reuse across evaluations;
  • for sparse queries, a query-time chain that keeps only recent data can be cheaper.

Scope and acceptance

In scope:

  • ExecutionTiming, Lifetime, PhysicalProperties, PhysicalCandidate::delivers_on, producer_satisfies_physical_requirements;
  • Stage 2 generation and producer filtering;
  • Stage 3's run_kind;
  • asap-cost;
  • the export.

Out of scope:

Acceptance:

Related

Activity

  1. added
    enhancementNew feature or request
    irPre-ASAP or post-ASAP intermediate representation
    optimizerWorkload optimization and plan selection
    on Nov 3, 2026
  2. changed the title [-]Physical properties: replace Materialization with timing × lifetime, and derive materialized and RunKind from them[/-] [+]Physical properties: replace Materialization with timing × lifetime (None / OneEvaluation / AcrossEvaluations) enums, with r^phys and α^phys[/+] on Nov 4, 2026
  3. changed the title [-]Physical properties: replace Materialization with timing × lifetime (None / OneEvaluation / AcrossEvaluations) enums, with r^phys and α^phys[/-] [+]Physical properties: replace Materialization with timing × lifetime (None / OneEvaluation / AcrossEvaluations) and a schedule for shareable results, with r^phys and α^phys[/+] on Nov 4, 2026
  4. self-assigned this
    on Nov 4, 2026
  5. zzylol commented on Nov 5, 2026

    @zzylol
    ContributorAuthor

    Executor disk storage for Disk-medium states is tracked in #1217 (decided 2026-11-05: Stage 2 keeps not offering Disk; until #1217 a Disk state executes in memory).

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Labels

enhancementNew feature or requestirPre-ASAP or post-ASAP intermediate representationoptimizerWorkload optimization and plan selection

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions