Covering index on a roll-upMedical device manufacturer, anonymized × red9CS-0269
A receivables roll-up stopped reading 440 million pages a day
The problem. A medical device manufacturer had a query summing invoice totals across its receivables tables, grouped by sales order, running about 1,280 times a day. Each execution averaged 191.06 ms, burned 1,405.04 ms of processor time, and read 343,779 pages, which came to roughly 440 million reads a day for one summing query.
What we did. We captured the plan and Query Store history, then created a nonclustered index on the status column the query filters, with the invoice column it sums included so the engine never leaves the index. A rollback script went over with it and the readings came from the same window.
Red9 · Performance Impact
Pages read per day
440M → 8,960
440,037,120 down to 8,960 at unchanged volume.
Per-run duration
1,470x
191.06 ms down to 0.13 ms.
Processor time, per run
1,405.04 → 0.13 ms
The summing work moved into the index, so the CPU cost went with it.
Duration
191.06 ms → 0.13 ms
1,470x shorter
Reads / run
343,779 → 7
440M to 8,960 daily
Executions
~1,280 / day
unchanged
Receivables roll-up
duration, per run
How the math works. The 1,470x is 191.06 ms over 0.13 ms. Per-execution reads went from 343,779 to 7, which across roughly 1,280 daily runs is 440,037,120 pages down to 8,960. CPU fell from 1,405.04 ms to 0.13 ms per run, and the manufacturer's report scores the whole change at 61,386x, a composite of theirs. Every one of those figures sits in the client’s Query Store history.
The result. The roll-up answers in about a tenth of a millisecond and its daily logical reads fell from 440,037,120 to 8,960. Two other queries on the same tables benefited from the same index without any further work.
The technical detail
What the review found. The query filtered receivables by status and summed a price column, with no index on the status column. Every one of its 1,280 daily executions therefore scanned the table and aggregated afterwards, at 343,779 reads a time.
What we changed (identifiers generalized for privacy):
-- Receivables roll-up: ~1,280x/day, 191.06 ms avg, 343,779 reads per run.
CREATE NONCLUSTERED INDEX IX_RED9_armast__status_fcinvoice
ON dbo.[armast] (fcstatus) INCLUDE (fcinvoice);
-- rollback: DROP INDEX IX_RED9_armast__status_fcinvoice provided
One key column and one included column: 0.13 ms per run and 7 reads, with a second query on the same table picking up the benefit for free.