test(db): pin the query plan for the monthly aggregates - #236
Merged
Merged
Conversation
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).
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
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_gateasserts the source shape (no datefunction 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 ratherthan fabricating one).
Changes
src/db.rs: newdb::tests::month_aggregate_queries_use_an_index_not_a_full_scan. On a migrated dbwith 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 showSCAN <table>:user_id), monthly usage count (ops),today-by-hour (ops), per-member
LEFT JOIN(admin).ur- that is what the planner prints for an aliasedtable; asserting the table name there is a false failure (found and fixed while writing this).
transactions(user_id, time, type, pts)has
transactions(user_id, time)as a prefix, so the olderidx_transactions_user_id_timeisprefix-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 theshape" and "the shape gets a SEARCH plan".
Tests
cargo testall green - 246 passed / 0 failed (was 245; +1)cargo fmt --checkexit 0cargo clippy --all-targets -- -D warningsclean on CI's stable toolchain (same pre-existing1.95.0-only
collapsible_matchdisclosure as before, out of this diff)Teeth
Removing the two new covering indexes (
idx_transactions_user_id_time_type_pts,idx_transactions_time_type_pts) frommigrate()reds:and the file was restored byte-identically (md5 asserted before/after). The live tree is green.
Checklist
test/month-aggregate-query-plan