Covering index on a date columnBeverage distributor, anonymized × red9CS-0110
A promotions query cut its daily reads from 9.1 million pages to 509,000
The problem. A beverage distributor ran a promotions query joining promotion sections, codes, and customers against an orders table, filtered on a sales-history date with no adequate index behind it. At roughly 34 runs a day it averaged 1,874.96 ms and 268,545 reads per execution, which came to about 9.1 million pages a day.
What we did. We created a nonclustered index on the sales-history date column with seven columns included, chosen so the query never leaves the index for the fields it returns. Query Store supplied the before-and-after readings.
Red9 · Performance Impact
Pages read per day
9.1M → 509K
9,130,530 down to 508,946 at unchanged volume.
Per-run duration
13.6x
1,874.96 ms down to 137.41 ms.
Processor time, per run
13x less
1,853.75 ms of CPU down to 137.37 ms, almost all of it read work.
Duration
1,874.96 ms → 137.41 ms
13.6x shorter
Reads / run
268,545 → 14,969
18x fewer
Executions
~34 / day
unchanged
Promotions query
duration, per run
How to read these. The 13.6x is 1,874.96 ms over 137.41 ms. Per-execution reads went from 268,545 to 14,969, which across roughly 34 daily runs is 9,130,530 pages down to 508,946. CPU tracked duration almost exactly, and logical reads fell from 268,545 to 14,969 alongside it. Query Store recorded all of it.
The result. The promotions query answers in under 140 milliseconds, and it stopped issuing 8.6 million logical reads a day. Because the included columns cover the output, the plan stays a seek as the orders table grows, and we retest it as the data shifts.
The technical detail
What the review found. The filter sat on a sales-history date on the orders table, and the existing indexes did not lead with that column, so the plan scanned and then looked up seven more fields per qualifying row. That combination produced 268,545 reads per execution.
What we changed (identifiers generalized for privacy):
-- Promotions query: ~34x/day, 1,874.96 ms avg, ~9.1M reads/day.
CREATE NONCLUSTERED INDEX IX_Red9_Orders_SalesHistoryDate
ON dbo.[Orders] (salesHistoryDate)
INCLUDE (isToDistributor, ticketNumber, isVoided, shippedDate,
toCustomerId, waitingForWhat, enteredById);
-- rollback: DROP INDEX IX_Red9_Orders_SalesHistoryDate provided
Leading with the filtered date and carrying the output columns turned the scan into a range seek: 137.41 ms and 14,969 reads a run.