Query / SP tuningLarge physician-led healthcare group, anonymized × red9CS-0256
A clinical data API cut from 86 seconds to a quarter-second
The problem. A stored procedure at the center of a physician-led healthcare group's clinical data API, FHIR.GetConditions, had slowed to about 86 seconds per call. It ran roughly 100 times a day and drove about 1.8 million reads each time, so the API that clinicians depend on was crawling.
What we did. We rewrote the stored procedure, replacing a correlated NOT IN pattern with a set-based join and NOT EXISTS, and added a covering index on the driving filter. Captured the before and after in the same folder.
Red9 · Performance Impact
SQL capacity reclaimed
~2.4 hrs / day
Reclaimed on a single stored procedure, on the same hardware.
Worst call, duration
343x
86.1 seconds down to 251 ms per call.
Disk reads removed43x1,822,625 down to 42,670 per call, total IO off the box.
Duration
86.1 s → 251 ms
343x
Disk reads
1,822,625 → 42,670
43x
Executions
~100 / day
unchanged
Stored proc
duration, per call
Where the numbers come from. Each speedup multiple is simply the old value over the new one (duration 86,100 ÷ 251). The ~2.4 hours reclaimed daily works out to about 100 runs a day at the ~86 seconds shaved off each one. Everything here traces back to what the client recorded on both sides of the change.
The result. The clinical API call now returns in about a quarter of a second and reads 42,670 pages instead of 1.8 million, giving the group back about 2.4 hours of SQL work a day with no hardware change.
The technical detail
What the review turned up. The FHIR.GetConditions procedure filtered a large clinical table through a correlated NOT IN subquery with no supporting index, so every call scanned the table, about 1.8 million reads, roughly 100 times a day.
What we changed (identifiers generalized for privacy):
-- Rewrote FHIR.GetConditions: NOT IN -> NOT EXISTS, set-based join,
-- and covered the driving filter so the proc seeks instead of scanning.
CREATE NONCLUSTERED INDEX IX_Conditions_patient_status
ON dbo.Conditions (patientId, statusCode) INCLUDE (onsetDate, code);
-- proc body: correlated NOT IN (...) rewritten as NOT EXISTS (...)
The rewrite plus the covering index turned an 86-second scan into a 251 ms seek, and cut reads from 1.8 million to 42,670 per call.