Index tuningOnline apparel seller, anonymized × red9CS-0097
An e-commerce stored procedure run 3,000 times a day, from 2.65 million reads to 3
The problem. An online apparel seller with a busy catalog and checkout path leaned on one stored procedure roughly 3,000 times a day, and each call ripped through 2,653,580 logical reads at about 1,075 ms a run. That single routine was pinning storage and stretching out every operation that touched it.
What we did. We captured the plan and statistics, then added a covering index matched to the procedure's filter and output columns, so the engine seeks a few rows instead of scanning the whole table. Before and after landed in the same capture.
Red9 · Performance Impact
Disk reads removed
~884,000x
2,653,580 logical reads per call down to 3.
Per-call duration
>1,000x
1,075 ms down to under 1 ms per run.
SQL capacity reclaimed
~53 min/day
Across ~3,000 daily runs of the same procedure, on the same hardware.
Disk reads
2,653,580 → 3
~884,000x less
Duration
1,075 ms → <1 ms
>1,000x
Executions
~3,000 / day
unchanged
How the numbers break down. Each multiple is the old value over the new one, so 2,653,580 reads divided by 3 lands near 884,000x. The ~53 minutes reclaimed each day is roughly 3,000 runs at the ~1,074 ms trimmed off each. Everything traces to the client's own captures on both sides of the change.
The result. The procedure now reads 3 pages instead of 2.65 million and returns in under a millisecond. Over roughly 3,000 daily runs that hands the retailer back about 53 minutes of SQL time a day, and the storage it used to burn is off the instance.
The technical detail
What the review turned up. The procedure filtered a large table with no supporting index, so every one of its ~3,000 daily calls scanned the table end to end, about 2,653,580 reads each time.
What we changed (identifiers generalized for privacy):
-- Procedure scanned the full table: 2,653,580 reads, ~1,075 ms, ~3,000x/day.
CREATE NONCLUSTERED INDEX IX_catalog_lookup_covering
ON dbo.[catalog_items] (/* filter cols */) INCLUDE (/* output cols */);
-- procedure rewritten to seek the covering index; DROP INDEX rollback provided
The covering index turned the scan into a seek: reads fell from 2,653,580 to 3, and the run dropped from about 1,075 ms to under one.