feat(kpihistory): add KpiRollupHourly table + EF config + migration (plan #22 T1)

New KpiRollupHourly entity is the hourly pre-aggregated series backbone folded
from raw KpiSample rows, letting long-range (30d/90d) trend reads scan ~60x fewer
rows. Same (Source, Metric, Scope, ScopeKey) series key as KpiSample plus
HourStartUtc bucket, folded Value, and MinValue/MaxValue/SampleCount fidelity
columns. UNIQUE IX_KpiRollupHourly_Series (upsert key + range-read cover, with the
default [ScopeKey] IS NOT NULL filter suppressed so Global rows participate) and
IX_KpiRollupHourly_Hour for purge. Non-partitioned, [PRIMARY], no DB-role restriction.

Claude-Session: https://claude.ai/code/session_01MtdgwpEeCUn6cUA5f1LMPj
This commit is contained in:
Joseph Doherty
2026-07-10 11:41:58 -04:00
parent 84112db344
commit 0f5e70fd35
6 changed files with 2344 additions and 0 deletions
@@ -149,6 +149,9 @@ public class ScadaBridgeDbContext : DbContext, IDataProtectionKeyContext
/// <summary>Gets the set of KPI samples (central tall/EAV KPI-history backbone).</summary>
public DbSet<KpiSample> KpiSamples => Set<KpiSample>();
/// <summary>Gets the set of hourly KPI rollups (pre-aggregated long-range trend backbone).</summary>
public DbSet<KpiRollupHourly> KpiRollupHourly => Set<KpiRollupHourly>();
// Data Protection Keys (for shared ASP.NET Data Protection across nodes)
/// <summary>Gets the set of data protection keys.</summary>
public DbSet<DataProtectionKey> DataProtectionKeys => Set<DataProtectionKey>();