Skip to content

perf(stats): draw the Statistics charts from the page's own metrics scan - #275

Merged
henry40408 merged 1 commit into
mainfrom
perf/stats-one-metrics-scan
Sep 13, 2026
Merged

henry40408 merged 1 commit into
mainfrom
perf/stats-one-metrics-scan

Conversation

@henry40408

Copy link
Copy Markdown
Owner

Summary

A visit to the Statistics page scanned idx_query_logs_ts_metrics twice and idx_query_logs_timestamp once. The server scanned the metrics index for the breakdowns. After the page loaded, the browser fetched the timeline, which scanned the same index again, and the heatmap, which scanned the timestamp index.

  • Database::stats_scan_since reads the metrics index once, starting at the earlier of the range window and the 30-day heatmap window. It returns the window readings plus a QuarterSeries: query counts per UTC quarter hour, with a separate boundary for each window.
  • The page embeds that series in <stats-page data-series data-bucket-secs>. app.js (timelineFromQuarters / heatmapFromQuarters) folds it into the viewer's calendar, so the page no longer requests its charts. The fold is exact because every UTC offset in use is a whole number of quarter hours.
  • Rows are streamed and folded in Rust instead of grouped in SQL. A grain that carries both the quarter and response_ms approaches one group per row, which would mean a temp b-tree as large as the window.
  • /api/stats/v2/timeline and /api/stats/v2/heatmap are unchanged for API callers.

Page misses

stats_page_miss_bench against a copy of a real 370k-row database (7-day data, default retention):

range=30d
  range_stats (breakdowns+latency+charts+domains)      6126       23.9
  top_clients                                     3618       14.1
  db_health                                         14        0.1
    timeline (API only)                           2153        8.4
    heatmap (API only)                            1387        5.4
    breakdowns alone                              2153        8.4
    top_domains alone                             3973       15.5
  PAGE TOTAL (whole visit)                        9758       38.1

Before this change, a visit cost breakdowns + top_domains + top_clients + db_health + timeline + heatmap = 13 298 pages. It now costs 9 758 (−27%). 90d reads the same as 30d because both cover the whole table. 7d goes from 12 430 to 9 300.

Tests

  • stats_db_test: the scan returns the same window readings as window_metrics_since. Folding its series reproduces timeline_multi_since and hourly_heatmap_since for eight offsets, including +5:30, +5:45 and −9:30, across all three bucket widths. Each window keeps its own boundary to the millisecond.
  • stats_page_miss_test: the page's scan costs no more than the window readings alone, and less than half of the three statements it replaces.
  • admin_api_test: the rendered page carries the series and the bucket width.
  • New e2e spec stats_charts.rs: runs the JavaScript folds in a real browser and compares them against the API for every range and all eight offsets.

The UI looks the same, so screenshots were not regenerated.

🤖 Generated with Claude Code

The page read idx_query_logs_ts_metrics for its breakdowns, then the
browser fetched the timeline (the same index again) and the heatmap
(idx_query_logs_timestamp). stats_scan_since now reads the metrics index
once and also returns per-quarter-hour counts on UTC boundaries, which the
page embeds and app.js folds into the viewer's calendar. The fold is exact
because every UTC offset in use is a whole number of quarter hours.

On a 370k-row database, a whole-table visit drops from 13 298 to 9 758
page misses. The API's timeline and heatmap endpoints are unchanged; a new
e2e spec checks the browser folds against them across ranges and offsets.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@codecov

codecov Bot commented Sep 13, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 99.08257% with 1 line in your changes missing coverage. Please review.
✅ Project coverage is 91.26%. Comparing base (94737c8) to head (6f8b5dd).

Files with missing lines Patch % Lines
src/db.rs 98.88% 1 Missing ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##             main     #275      +/-   ##
==========================================
+ Coverage   91.18%   91.26%   +0.07%     
==========================================
  Files          31       31              
  Lines       11224    11329     +105     
==========================================
+ Hits        10235    10339     +104     
- Misses        989      990       +1     

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

@henry40408
henry40408 merged commit 55c68ea into main Sep 13, 2026
7 checks passed
@henry40408
henry40408 deleted the perf/stats-one-metrics-scan branch September 13, 2026 03:31
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