Skip to content

feat: reuse typed prepared plans and reduce execution overhead - #383

Open
KKould wants to merge 8 commits into
mainfrom
feat/prepared-plan
Open

KKould wants to merge 8 commits into
mainfrom
feat/prepared-plan

Conversation

@KKould

@KKould KKould commented Sep 23, 2026 •

Copy link
Copy Markdown
Member

What problem does this PR solve?

The old prepare path cached only a parsed SQL Statement: each execution still bound and optimized the query. Parameterized INSERT ... VALUES was also limited by bind-time constant evaluation. This PR makes prepared execution reuse a typed plan and updates the dependent execution paths.

Issue link: N/A

What is changed and how it works?

  1. Prepare and reuse plans (d9e8766): Database::prepare / DBTransaction::prepare take SQL plus positional parameter types and produce a PreparedPlan containing a bound, optimized plan and its arena. execute supplies values, clones the logical plan, and runs it without repeating parsing/binding/optimization. Placeholders are typed $1, $2, etc.; selected index ranges are bound and, when possible, specialized from residual predicates for the current parameter values.
  2. Rework INSERT / VALUES (d9e8766): retain row expressions as ExprRef in ValuesOperator instead of requiring bind-time constants. Resolve explicit DEFAULT while binding; evaluate and cast VALUES expressions per execution, then apply missing-column defaults and target-column length/nullability checks in Insert. This enables expressions and positional parameters in prepared INSERT ... VALUES, as well as expression-based standalone VALUES.
  3. Bind parameters per execution (db7d064): add ParamArena over the immutable prepared PlanArena, copying and replacing only parameter-dependent expressions; propagate MetaArena through the execution path so repeated executions do not mutate the cached plan. Index lookups are bound on the execution-local plan.
  4. Reduce execution and index-key overhead (45e3b79): keep ExecNodes in place instead of moving them out of the arena on every next_tuple; use arena-backed rewrite for projection/index expressions. Simplify DataValue::Tuple while deriving lower/upper prefix-bound semantics from range context during comparison and index-key encoding; restore tuple-buffer reuse in SeqScan and IndexScan.
  5. Update consumers and coverage: TPCC backends now cache PreparedPlans with explicit parameter/result types and positional values; SQLite adapts to the shared parameter IDs. Add prepared-plan/index-range unit tests and SQL logic cases for VALUES, INSERT, grouping and indexed predicates.

Code changes

  • Has Rust code change
  • Has CI related scripts change

Check List

Tests

  • Unit test — cargo test --lib --features decimal (426 passed)
  • Integration test — ran values.slt, group_by.slt, where_by_index.slt, where_by_index_explain.slt through sqllogictest-test
  • Manual test
  • No code

Side effects

  • Performance regression: Consumes more CPU
  • Performance regression: Consumes more Memory
  • Breaking backward compatibility — public binder::prepare / db::prepare (AST preparation) and Database::execute / DBTransaction::execute signatures change to the typed PreparedPlan API.

Note for reviewer

cargo fmt --all -- --check passes. The four-variant 720-second TPCC results are recorded in tpcc/README.md; this run used --cool-temp-c 75 because the machine idled above the runner's default 65°C gate.

Performance follow-ups (not addressed here):

  • Recursive ScalarExpression::eval creates temporary DataValues and evaluates binary/cast nodes one at a time. A no-table prepared arithmetic microbenchmark shows nontrivial per-expression execution cost; benchmark a specialized/compiled evaluation path separately.
  • ParamArena::new traverses the entire prepared expression arena on every execution, even if only a few expressions depend on parameters. Investigate caching parameter-dependent expression references to avoid this scan.

Redundant casts/projections are not optimized by this PR.

@codecov

codecov Bot commented Sep 23, 2026 •

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 94.02368% with 217 lines in your changes missing coverage. Please review.
✅ Project coverage is 93.09%. Comparing base (357cde1) to head (488c19d).

Files with missing lines Patch % Lines
src/expression/range_detacher.rs 90.43% 55 Missing ⚠️
src/planner/arena.rs 74.86% 45 Missing ⚠️
src/types/value.rs 87.50% 17 Missing ⚠️
src/db/prepared.rs 96.32% 16 Missing ⚠️
src/expression/evaluator.rs 91.97% 13 Missing ⚠️
src/expression/simplify.rs 83.67% 8 Missing ⚠️
.../optimizer/rule/normalization/combine_operators.rs 90.00% 8 Missing ⚠️
src/binder/parser.rs 95.28% 5 Missing ⚠️
src/function/lower.rs 58.33% 5 Missing ⚠️
src/function/upper.rs 58.33% 5 Missing ⚠️
... and 16 more
Additional details and impacted files
@@            Coverage Diff             @@
##             main     #383      +/-   ##
==========================================
- Coverage   93.18%   93.09%   -0.09%     
==========================================
  Files         257      258       +1     
  Lines       45852    47487    +1635     
==========================================
+ Hits        42727    44209    +1482     
- Misses       3125     3278     +153     
Flag Coverage Δ
rust 93.09% <94.02%> (-0.09%) ⬇️

Flags with carried forward coverage won't be shown. Click here to find out more.

Files with missing lines Coverage Δ
src/binder/aggregate.rs 97.68% <100.00%> (ø)
src/binder/alter_table.rs 100.00% <ø> (ø)
src/binder/analyze.rs 96.00% <ø> (ø)
src/binder/copy.rs 71.73% <ø> (ø)
src/binder/create_index.rs 90.47% <ø> (ø)
src/binder/create_table.rs 87.67% <ø> (ø)
src/binder/create_view.rs 100.00% <ø> (ø)
src/binder/delete.rs 100.00% <ø> (ø)
src/binder/describe.rs 100.00% <ø> (ø)
src/binder/distinct.rs 98.50% <100.00%> (ø)
... and 157 more

... and 2 files with indirect coverage changes

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

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