Skip to content

rust: Reduce size of some huge common objects: Plan, PlanNode, Expr<Raw>#35292

Closed
def- wants to merge 3 commits intoMaterializeInc:mainfrom
def-:pr-memory-optimizations
Closed

rust: Reduce size of some huge common objects: Plan, PlanNode, Expr<Raw>#35292
def- wants to merge 3 commits intoMaterializeInc:mainfrom
def-:pr-memory-optimizations

Conversation

@def-
Copy link
Contributor

@def- def- commented Mar 2, 2026

Extracted and cleaned up from #35255

@github-actions
Copy link

github-actions bot commented Mar 2, 2026

Thanks for opening this PR! Here are a few tips to help make the review process smooth for everyone.

PR title guidelines

  • Use imperative mood: "Fix X" not "Fixed X" or "Fixes X"
  • Be specific: "Fix panic in catalog sync when controller restarts" not "Fix bug" or "Update catalog code"
  • Prefix with area if helpful: compute: , storage: , adapter: , sql:

Pre-merge checklist

  • The PR title is descriptive and will make sense in the git log.
  • This PR has adequate test coverage / QA involvement has been duly considered. (trigger-ci for additional test/nightly runs)
  • If this PR includes major user-facing behavior changes, I have pinged the relevant PM to schedule a changelog post.
  • This PR has an associated up-to-date design doc, is a design doc (template), or is sufficiently small to not require a design.
  • If this PR evolves an existing $T ⇔ Proto$T mapping (possibly in a backwards-incompatible way), then it is tagged with a T-proto label.
  • If this PR will require changes to cloud orchestration or tests, there is a companion cloud PR to account for those changes that is tagged with the release-blocker label (example).

@def- def- force-pushed the pr-memory-optimizations branch from 9bae068 to 4ac0e5c Compare March 2, 2026 12:20
def- and others added 3 commits March 2, 2026 13:26
Box `Statement<Raw>` in DeclarePlan/PreparePlan (eliminating the ~832-byte
AST inline), then box 17 Plan variants larger than 200 bytes. SelectPlan
(184 bytes) is kept unboxed as the hot-path variant for every SELECT query.

The Plan enum represents every SQL statement type. Before this change, even
a simple `SELECT 1` allocated ~1888 bytes on the stack for the Plan. After:
184 bytes — a 90% reduction. DDL/EXPLAIN/SUBSCRIBE operations pay one extra
heap allocation, negligible compared to their inherent catalog transaction
cost.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Box 9 large inline fields in PlanNode<T> (GetPlan, JoinPlan,
KeyValPlan, ReducePlan, TopKPlan, and MapFilterProject in 4 positions).
These are constructed once during plan lowering and read during
dataflow rendering, so the extra indirection is negligible.

PlanNode is the LIR stored per-dataflow on every compute worker,
persisting in memory for the lifetime of each dataflow. The 73%
size reduction (384→104 bytes) reduces per-node memory across all
active dataflows.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
…riants

Two complementary optimizations that shrink the core AST Expr enum:

1. Expr::Function(Function<T>) → Function(Box<Function<T>>).
   Function<Raw> is 240 bytes and was the single largest variant,
   inflating the entire enum. Boxing reduces it to 8 bytes inline.

2. Expr::Cast { data_type: T::DataType } → { data_type: Box<T::DataType> }.
   RawDataType can be up to ~48 bytes; boxing reduces to 8 bytes.

Expr<Raw> is the most numerous AST node type — every expression in
every SQL query is represented as one. The savings compound because
Expr is stored recursively: every Vec<Expr<T>> element and every
Box<Expr<T>> allocation saves 168 bytes.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@def- def- force-pushed the pr-memory-optimizations branch from 4ac0e5c to a5310ae Compare March 2, 2026 13:26
@def- def- closed this Mar 2, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant