Skip to content

Serve the daily players chart from a per-day totals table - #30

Merged
needs merged 1 commit into
masterfrom
fix-all-time-chart-perf
Aug 24, 2026
Merged

Serve the daily players chart from a per-day totals table#30
needs merged 1 commit into
masterfrom
fix-all-time-chart-perf

Conversation

@needs

@needs needs commented Aug 24, 2026

Copy link
Copy Markdown
Owner

Counting PlayerDay rows per day meant a sequential scan of every monthly partition, so the home page's all-time range took ages — and no index could have helped, since Postgres has no index-skip-scan for aggregates. This adds a GlobalDay table holding one row per rolled-up day, written inside the rollup transaction and backfilled by the migration, then reads it from the chart, the status page, and the backfill worker's rolled-up-day scan (which ran the same unfiltered groupBy on every tick). The API response now carries Cache-Control, so switching back to a range already viewed is served from the browser cache. Chart labels take the year once the range needs one — MMM d, then MMM d, yyyy across a year boundary, then MMM yyyy past a year — and are built from the UTC calendar day, which also fixes every label rendering a day early west of Greenwich. Verified against a local replica seeded with 1231 days: every range now serves in 5–8 ms.

🤖 Generated with Claude Code

Counting PlayerDay rows per day meant a sequential scan of every
monthly partition, so the home page's all-time range took ages. No
index could have helped: Postgres has no index-skip-scan for
aggregates, so even a covering index still walks every entry. Add a
GlobalDay table holding one row per rolled-up day, written inside the
rollup transaction and backfilled by the migration, and read it from
the chart, the status page, and the backfill worker's rolled-up-day
scan, which ran the same unfiltered groupBy on every tick.

The API response now carries Cache-Control, so switching back to a
range already viewed is served from the browser cache. Chart labels
take the year once the range needs it: MMM d, then MMM d, yyyy across
a year boundary, then MMM yyyy past a year. They are built from the
UTC calendar day, which also fixes every label rendering a day early
west of Greenwich.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@needs
needs merged commit 63c84ad into master Aug 24, 2026
1 check 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