Parameter Sniffing

Status: Reviewed (deep-dive v1)
Stack note: Warehouse usp_* boards (SQL-12) compile with the first parameter set — a tiny @SqlInstanceId plan can torture the “all instances” call (or the reverse). Ties to SQL-16/20.
Goal: Spot sniffing, fix with measured options — not cargo-cult RECOMPILE on everything.


Quick chooser

Symptom Likely sniffing? First move
Same proc fast in SSMS, slow in Blazor Often (different params / settings) Actual plans both ways; QS (SQL-20)
Fast after deploy, slow next morning Stats + new sniff Compare plans in QS
Only bad when @Id IS NULL (all rows) Classic Separate proc or RECOMPILE on that path
Always slow Missing index / blocking — not sniffing SQL-16 / SQL-18

What’s going on

SQL Server caches a plan optimized for the sniffed parameter values at compile. Skewed estates (one huge instance, many tiny) make one plan a bad fit for others.


Mitigations (pick smallest that works)

  1. Fix the query/index so one plan is good (best)
  2. OPTION (RECOMPILE) on the statement — fresh plan each call; OK for heavy boards called moderately
  3. Local variables — assign params to locals (classic blindfold; can help or hurt)
  4. OPTIMIZE FOR (@p UNKNOWN) / known value — deliberate; document
  5. Split procsGetBoard vs GetBoardForInstance
  6. QS force plan — temporary bridge only (SQL-20)
-- targeted recompile on the hot statement
SELECT … FROM dbo.Alert a
WHERE (@SqlInstanceId IS NULL OR a.SqlInstanceId = @SqlInstanceId)
OPTION (RECOMPILE);
-- optimize for unknown (density-based)
OPTION (OPTIMIZE FOR UNKNOWN);

Estate habits


Tiny lab

  1. Call board with selective id → save plan
  2. Call with NULL (all) → compare
  3. Add OPTION (RECOMPILE) — confirm both acceptable

Done when


SQL Dude — SQL-24 Parameter Sniffing v1