Skip to content

test(db): pin the query plan for the monthly aggregates - #236

Merged
argszero merged 1 commit into
mainfrom
test/month-aggregate-query-plan
Sep 14, 2026
Merged

argszero merged 1 commit into
mainfrom
test/month-aggregate-query-plan

Conversation

@argszero

Copy link
Copy Markdown
Owner

Summary

Pin the query plan for the monthly aggregates, completing acceptance item 2 of the perf rant
(2026-09-14T16:51:14): "对月度聚合 EXPLAIN QUERY PLAN 不得出现 SCAN transactions".

#234 fixed the predicates and added the indexes, and perf_gate asserts the source shape (no date
function wraps a time column). But shape alone is not enough: if the covering indexes were dropped,
the source would still look right and the suite would stay green. This PR adds the plan-level half.

Related Issue

Follow-up acceptance item of rant 2026-09-14T16:51:14; no GitHub issue exists (left empty rather
than fabricating one).

Changes

  • src/db.rs: new db::tests::month_aggregate_queries_use_an_index_not_a_full_scan. On a migrated db
    with 3000 rows spread over the last 180 days (so the month window is ~1/6 of the table and the index
    is genuinely attractive), each rewritten shape must show SEARCH <table> and must not show
    SCAN <table>:
    • per-user month consume (wallet), global month-in (ops, no user_id), monthly usage count (ops),
      today-by-hour (ops), per-member LEFT JOIN (admin).
    • the admin case asserts on the alias ur - that is what the planner prints for an aliased
      table; asserting the table name there is a false failure (found and fixed while writing this).
  • Records the rant's open question on index de-duplication: the new transactions(user_id, time, type, pts)
    has transactions(user_id, time) as a prefix, so the older idx_transactions_user_id_time is
    prefix-redundant. Deliberately not dropped here (minimal change) - a follow-up candidate.

Honest scope note: this test pins the plan permitted for the range shape; production is bound to
that shape by perf_gate. Neither half alone is sufficient - together they assert "production has the
shape" and "the shape gets a SEARCH plan".

  • Config/data-structure changes are mirrored into the example file (n/a - test-only)

Tests

  • cargo test all green - 246 passed / 0 failed (was 245; +1)
  • cargo fmt --check exit 0
  • cargo clippy --all-targets -- -D warnings clean on CI's stable toolchain (same pre-existing
    1.95.0-only collapsible_match disclosure as before, out of this diff)
  • New test added (1)

Teeth

Removing the two new covering indexes (idx_transactions_user_id_time_type_pts,
idx_transactions_time_type_pts) from migrate() reds:

db::tests::month_aggregate_queries_use_an_index_not_a_full_scan
db::tests::transactions_perf_indexes_created_on_migrate

and the file was restored byte-identically (md5 asserted before/after). The live tree is green.

Checklist

  • Branch naming follows the convention: test/month-aggregate-query-plan
  • Commit message uses Conventional Commits
  • Single responsibility, minimal change

Rant 2026-09-14T16:51:14, acceptance item 2: "对月度聚合 `EXPLAIN QUERY PLAN`
不得出现 `SCAN transactions`".

The `perf_gate` module added in #234 only asserts the source *shape* (no date
function wraps a time column). If the covering indexes were dropped, the shape
would still be right and the suite would stay green - the plan-level half was
missing. This adds it: against a migrated db holding 3000 rows spread over 180
days, each rewritten query shape must show `SEARCH <table>` and must not show
`SCAN <table>`.

Five shapes: per-user month consume (wallet), global month in (ops, no user_id),
monthly usage count (ops), today-by-hour (ops), and the per-member LEFT JOIN
(admin). The admin case asserts on the **alias** (`ur`) because that is what the
planner prints for an aliased table - asserting the table name there reports a
false failure.

Also evaluates the rant's open question on index de-duplication: the new
`transactions(user_id, time, type, pts)` has `transactions(user_id, time)` as a
prefix, so the older `idx_transactions_user_id_time` is prefix-redundant. Left in
place (minimal change) and recorded as a follow-up candidate, not dropped here.

Honest scope note: this test pins the *permitted plan for the range shape*; the
production source is bound to that shape by `perf_gate`. Neither alone would be
enough - together they mean "production has the shape" and "the shape gets a
plan with a SEARCH".

Tests: 245 -> 246 passed / 0 failed. Teeth verified: removing the two new
covering indexes reds this test (and the v12/v14 index-list test), and the file
was restored byte-identically (md5 asserted).
@argszero
argszero merged commit 83ecf4e into main Sep 14, 2026
1 check passed
@argszero
argszero deleted the test/month-aggregate-query-plan branch September 14, 2026 11:27
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