perf(kpi-history): time-sliced batched purge replaces the single daily mega-DELETE
This commit is contained in:
+17
-4
@@ -64,9 +64,22 @@ public sealed class KpiHistoryRepository : IKpiHistoryRepository
|
||||
/// <inheritdoc />
|
||||
public async Task<int> PurgeOlderThanAsync(DateTime before, CancellationToken cancellationToken = default)
|
||||
{
|
||||
// Set-based delete — no entity materialisation; returns the rows affected.
|
||||
return await _context.KpiSamples
|
||||
.Where(s => s.CapturedAtUtc < before)
|
||||
.ExecuteDeleteAsync(cancellationToken);
|
||||
// Time-sliced batches: each DELETE covers at most one hour of samples, capping the
|
||||
// lock/log footprint per statement (arch-review 04, P4 — steady state is ~1 day of
|
||||
// rows/day; after an outage the catch-up would otherwise be one giant transaction).
|
||||
var total = 0;
|
||||
var floor = await _context.KpiSamples.Where(s => s.CapturedAtUtc < before)
|
||||
.MinAsync(s => (DateTime?)s.CapturedAtUtc, cancellationToken);
|
||||
while (floor is not null && floor < before)
|
||||
{
|
||||
var ceiling = floor.Value.AddHours(1) < before ? floor.Value.AddHours(1) : before;
|
||||
total += await _context.KpiSamples
|
||||
.Where(s => s.CapturedAtUtc < ceiling)
|
||||
.ExecuteDeleteAsync(cancellationToken);
|
||||
floor = await _context.KpiSamples.Where(s => s.CapturedAtUtc < before)
|
||||
.MinAsync(s => (DateTime?)s.CapturedAtUtc, cancellationToken);
|
||||
}
|
||||
|
||||
return total;
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user