Online covering indexWholesale distributor, anonymized × red9CS-0164
A work-order query stopped reading 2.16 billion pages a day
The problem. A wholesale distributor had a large multi-join query against its work-order lines table running about 58 times a day. Each execution averaged 22,067.73 ms, burned 17,316.24 ms of processor time, and the statement was accounting for 2,160,753,402 reads a day. 22 seconds for an operational query is the kind of number people stop mentioning and start planning around.
What we did. We built a covering index on the two columns the query joins and filters on, with the two quantity columns it returns included, and created it online with a fill factor of 80 so nothing had to stop. Query Store recorded before and after.
Red9 · Performance Impact
Pages read per day
2.16B → 879,744
A 2,456-fold drop at unchanged query volume.
Per-run duration
121x
22,067.73 ms down to 180.91 ms.
Processor time, per run
217x less
17,316.24 ms of CPU down to 79.94 ms, with about 21 minutes of SQL time a day recovered.
Duration
22,067.73 ms → 180.91 ms
121x shorter
Reads / day
2,160,753,402 → 879,744
2,456x fewer
CPU
17,316.24 ms → 79.94 ms
217x less
Work-order query
duration, per run
How the math works. The 121x is 22,067.73 ms over 180.91 ms and the 217x is 17,316.24 ms of CPU over 79.94 ms. Daily reads went from 2,160,753,402 to 879,744, which is the 2,456-fold figure; per execution the summary table shows 37,254,369 down to 15,168. The 21 minutes a day comes from about 58 runs at the 21.9 seconds each one stopped taking.
The result. The query answers in under two tenths of a second and the estate stopped moving more than two billion pages a day for it. Because the index was built online, it went in without a maintenance window.
The technical detail
What the review found. The work-order lines table had no index leading with the join column, so every execution scanned it and then looked up the quantity fields row by row. At that table size the per-execution read count reached 37 million.
What we changed (identifiers generalized for privacy):
-- Work-order query: ~58x/day, 22,067.73 ms avg, ~2.16B reads/day.
CREATE NONCLUSTERED INDEX IX_Red9_WorkOrderLines_OrderLine_Source
ON dbo.[WorkOrderLines] (orderLineId, productionSource)
INCLUDE (sentWorkOrderQuantity, workOrderQuantity)
WITH (FILLFACTOR = 80, ONLINE = ON);
-- rollback: DROP INDEX IX_Red9_WorkOrderLines_OrderLine_Source provided
Covering the join and the output turned the scan into a seek: 180.91 ms a run, 79.94 ms of CPU, and 879,744 reads a day.