Skip to content

Fold logical AND, OR and NOT through the Scheme optimizer - #1072

Merged
carli2 merged 4 commits into
masterfrom
perf/step-query
Oct 11, 2026
Merged

carli2 merged 4 commits into
masterfrom
perf/step-query

Conversation

@carli2

@carli2 carli2 commented Oct 10, 2026 •

Copy link
Copy Markdown
Contributor

Logical AND, OR and NOT expressions currently retain provably constant branches until physical code optimization, carrying unnecessary boolean trees through decorrelation and later planning passes. Fold complete constant expressions while combining bound logical rewrites, using the existing Scheme optimizer rather than a separate SQL truth-value implementation.

Add tryfold(code): it accepts a raw Scheme expression and returns its constant value, or raises when folding fails. It uses the optimizer's existing function declaration metadata and lazy evaluation rules. It clones the input AST and decodes only constant values/data encodings; it never executes residual code. SCM/Go has no knowledge of frontend expression/type/collation records. Each frontend in lib/ owns its metadata; this boundary is now explicit in INVARIANTS.md.

The logical planner tries this interface for boolean operators with literal operands and retains the original AST on failure. For example, 0 AND expression can become false, while throwing_expression AND 0 must retain its earlier operand and its error. The same distinction applies to OR. SQL name binding still validates the complete expression first, and collected stages/sources remain available to the existing dependency-demand pass. Mixed expressions that are not completely constant stay as logical ASTs.

This also fixes the failing normal/JIT SQL tests: the earlier PR implementation incorrectly suppressed invalid-REGEXP errors preceding a later false/true operand.

Manual A/B measurements

The workload contains ordered SELECTs with OR-connected LIKE predicates, IN (SELECT ... UNION SELECT ...) membership, and nested correlated EXISTS/scalar projections. The persisted fixture contains 80,000 outer rows and 40,000 membership rows. The unbounded SELECT case complements the existing LIMIT cases; two additional actor/session variants verify permission results.

Compared unchanged development baseline beb30f0c298e82b340c2c6de242b8b364bf6d4bc with the final implementation using run_sql_tests.py --perf-ab. Each worktree uses its own build, the same candidate test specification, and independent copies of the same baseline-prepared fixture. Both roles use warmup: 0, timing_samples: 3, timing_aggregation: total: one initial query plus two further queries, in identical case order. Repeated the complete comparison with a second fresh fixture.

SQL workload Run 1 baseline → candidate Change Run 2 baseline → candidate Change
Ordered SELECT, LIMIT 1 3964.544 → 3705.992 ms −258.552 ms / −6.5% 4143.391 → 3957.555 ms −185.836 ms / −4.5%
Ordered SELECT, LIMIT 72 1659.063 → 1552.293 ms −106.770 ms / −6.4% 1763.196 → 1615.823 ms −147.373 ms / −8.4%
Ordered SELECT, no LIMIT 1479.368 → 1344.528 ms −134.840 ms / −9.1% 1555.561 → 1449.114 ms −106.447 ms / −6.8%

These measurements include initial compilation and statistics-driven recompilation. The final optimized physical Scheme program is unchanged after normalizing generated structural hashes: the gain is in query compilation.

Validation

  • 187 targeted SQL cases pass across boolean tautology folding, navigation permission probes, EXISTS, scalar subselect clauses, and NULL/short-circuit semantics.
  • All five cases in ordered-fulltext-membership.yaml pass, including restricted and unprivileged actors.
  • Targeted Go optimizer tests pass, covering raw constants, nested constant data, failed folding without AST mutation, lazy/error ordering, and declared nonfoldable functions that must never execute, including a nonconstant prefix before a constant result.
  • Inspected EXPLAIN, EXPLAIN IR, EXPLAIN PHYSICAL, EXPLAIN REORDER and EXPLAIN COMPILE for the final implementation; previously measured extracted scan/RecSet/projection components through /scm.
  • Regenerated builtin JIT support with make jitgen; Go formatting, the changed Scheme file formatter check and git diff --check pass.
  • The complete SQL suite, native JIT suite and broader performance regression checks run in PR CI, following the repository performance workflow.

@carli2 carli2 changed the title Reduce compilation work for generated navigation permission checks Fold boolean literals earlier during logical query rewriting Oct 10, 2026
@carli2 carli2 changed the title Fold boolean literals earlier during logical query rewriting Fold logical AND, OR and NOT through the Scheme optimizer Oct 10, 2026
@carli2
carli2 merged commit 6005c17 into master Oct 11, 2026
36 checks passed
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