Repository navigation
Route get_top_procedures_by_cpu and the Top Procedures grid to the hourly rollup (#4231) - #4413
Merged
Merged
Conversation
…urly rollup (#4231) Refs #4231. Copies stage 3a's routing pattern (#4396) for procedure_stats: TopProceduresHourlySql over procedure_stats_hourly/procedure_stats_interval_hourly via RollupCoverage.StitchedRelationSql, GetTopProceduresByCpuRoutedAsync exposing the tier, the MCP tool's tier_used/precision_note, and the Viewer's tiered read plus grid header suffix.
erikdarlingdata
marked this pull request as ready for review
September 26, 2026 13:18
This was referenced Sep 26, 2026
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.
Refs #4231.
Why
get_top_procedures_by_cpuand the Viewer's Top Procedures grid readprocedure_statsdirectly, which a store with the rollups armed drops after a few days. Once the window ages past raw's floor the read should fall back to the hourly rollup rather than silently returning nothing, the same fix already shipped forget_top_queries_by_cpu(#4396).What changes
DarlingDataReader.TopProceduresHourlySql, grouped by(database_name, schema_name, object_name)and ranked bySUM(worker_time_sum) DESC, with its FROM clause built only throughRollupCoverage.StitchedRelationSql— never a literalprocedure_stats_hourlyname.GetTopProceduresByCpuRoutedAsyncpicks Raw or Hourly viaRetentionTierRouter.ResolveoverRollupCoverage.For(ProcedureStatsHourlyView, ProcedureStatsDailyView); a Daily verdict is clamped to Hourly (out of scope for this change).GetTopProceduresByCpuAsyncis now a thin wrapper over the routed read, so every existing caller keeps working.get_top_procedures_by_cpuMCP payload gainstier_used("raw"/"hourly") andprecision_note. The rollup carries noobject_type,sql_handle, orplan_handle, so an hourly-routed row'sobject_typeis reported asnull(never the empty-string default) with a note explaining why.window_truncated/effective_start) now run, and are meaningful, only for the raw tier — an hourly-routed read never touchedprocedure_stats, so probing its floor would answer a fact about a table the read never consulted.ViewerDataService.GetTopProceduresByCpuTierAsync(routes the same way, over the same coverage pair) and the Top Procedures grid header now appends the hourly-tier disclosure suffix when routed, exactly like the Queries grid already does.Deviations
procedure_statshas nohost_object_nameand no query-text lookup, so this change is smaller than stage 3a: no follow-up per-row text query, norollUpByHostObject/min_dopparameters to disable at the hourly tier.ComposeStoreAvailabilitycaches rollup coverage perNpgsqlDataSourcefor 5 minutes) applies identically here — the new live test uses a fresh data source for its post-refresh, post-purge call, same asTopQueriesHourlyRoutingLiveTests.Test plan
TopProceduresHourlyRoutingTests(new, source-level): SQL-shape pin (GROUP BY database_name, schema_name, object_name, noobject_type,ORDER BY SUM(worker_time_sum) DESC,$FROM$placeholder present) and a source pin thatGetTopProceduresByCpuHourlyAsyncbuilds its FROM clause only throughRollupCoverage.StitchedRelationSql, never namingprocedure_stats_hourly/procedure_stats_interval_hourlyliterally. RED on dev confirmed: building this file against commit30760481a(dev tip, stage 3a merged) fails to compile —DarlingDataReader.TopProceduresHourlySql/TopProceduresHourlyFromPlaceholderdo not exist. GREEN on this branch: 2/2 passed in-process (Darling.Tests.dll on macOS).TopProceduresHourlyRoutingLiveTests(new, live, own scratch database per Six live Darling.Tests classes run outside the live-postgres collection, producing moving cross-class flakes on a shared store #1776): seeds three(schema, object)groups into rawprocedure_stats, confirms a routed call reportsRetentionTier.Raw; refreshesprocedure_stats_interval_hourlyvia the product's ownrefresh_continuous_aggregate, purges raw's rows for the window, and confirms a routed call on a freshNpgsqlDataSourcereportsRetentionTier.Hourlywith totals matching raw's for every group. A second test drivesget_top_procedures_by_cpuend to end and assertstier_used/precision_noteon both tiers, and thatobject_typeisnullon every hourly-routed row. RED on dev confirmed: same commit, same compile failure (GetTopProceduresByCpuRoutedAsyncdoes not exist). GREEN on this branch, against a throwaway TimescaleDB 2.30.1 container: 2/2 passed.TopQueriesHourlyRoutingTests(2/2) andTopQueriesHourlyRoutingLiveTests(2/2) both still pass unchanged.Darling.Tests.csprojandLite.Tests.csprojbuild 0 errors / 0 (unrelated pre-existing) warnings with-p:EnableWindowsTargeting=true.Darling.Tests/Lite.Teststargetnet10.0-windowsand cannot run under CI on this machine's OS; they build here and CI decides them on Windows.Measurement
Seed: 10,081 rows at 1-minute grain over 500
(schema, object)groups across a 7-day window (2026-01-01–2026-01-08), matching stage 3a's seed scale.EXPLAIN (ANALYZE, BUFFERS)for the ranking query, 1 cold + 3 warm runs, against a standalone table pair built directly from the product's own SQL shapes (not through migrations, to keep the measurement fast):procedure_stats-shaped table): Seq Scan + HashAggregate, 206 buffer hits, Execution Time 2.79 ms (cold).procedure_stats_hourly-shaped table, pre-aggregated at the same grain for this seed): Seq Scan + HashAggregate, 156 buffer hits, Execution Time 2.33–3.06 ms (3 warm runs).At this seed scale the two are comparable because the hourly rollup here holds the same row count as raw (no compression from bucketing distinct minutes into hours happened in this synthetic seed); the real-world win is that raw ages out entirely after its retention window while the hourly rollup keeps answering, which is what the live routing test proves.
CHANGELOG entry
SECTION: Changed
ENTRY:
get_top_procedures_by_cpuand the Top Procedures grid now route to the hourly rollup once raw ages past its retention window, instead of returning nothing ([Route get_top_procedures_by_cpu and the Top Procedures grid to the hourly rollup (#4231) #4413]) - Mirrors the routing already shipped forget_top_queries_by_cpu; the payload discloses which tier answered and what an hourly-routed row is missing (object_type).REF:
[Route get_top_procedures_by_cpu and the Top Procedures grid to the hourly rollup (#4231) #4413]: Route get_top_procedures_by_cpu and the Top Procedures grid to the hourly rollup (#4231) #4413