skip to content

Optimizer-chosen plans can change on their own as data, statistics, or engine versions shift. For a system where some queries must never regress, how do you decide between letting the optimizer keep adapting and pinning plans, and what does that policy cost you?

level: principalimportance: nice to knowfreq 30%

answer

  1. Adaptive = usually right, occasionally catastrophic, no change event
  2. Pinned = predictable, predictably stale later
  3. Pin for variance, not for slowness
  4. Detection (plan hash + p99) beats pinning
  5. Every pin: owner, reason, review date, removal test

basics

~20 s

Adaptivity and predictability trade off directly. Let the optimizer adapt by default, since it tracks data change; pin plans only for a small set of critical queries where a regression is unacceptable. Pinning freezes today's plan — including out of better future plans — so each pin needs an owner, a review date, and monitoring.

solid answer

~60 s

Treat it as a **risk budget**, not a preference. Default to adaptivity: the optimizer re-plans as data changes, and most queries benefit. Pinning everything guarantees today's plan forever, including as the data outgrows it. Pin selectively where the blast radius justifies it — a handful of queries on a critical path where a plan flip means an outage, not a slowdown. Mechanisms differ (hints, plan baselines, forced plans, query-store forcing); the semantics you care about are: does it *force* one plan or merely *bound* the search, and does it fail safe if the plan becomes invalid. The real programme is **detection**, not pinning: capture plan identity and per-query duration percentiles so a plan change is a visible event, with an automatic revert path where the engine offers one. Costs of pinning: frozen plans go stale as data grows; upgrades must revalidate every pin; pins hide the underlying estimation defect; and they accumulate as undocumented debt. Every pin needs an owner, a reason, a review date, and a removal test.

go deeper

for a junior

Know that plans can change by themselves as data and statistics change, and that engines provide ways to force a specific plan.

for a middle

Explain why plan changes happen, name the mechanisms, and note that forcing a plan trades adaptability for predictability.

for a senior

Segment the workload by blast radius, prefer mechanisms that bound rather than freeze the search, and insist on plan-change monitoring plus a revert path.

for a principal

Own the policy: allocate a risk budget across the workload, invest in detection and estimation quality before pinning, define governance for pins (owner, expiry, upgrade revalidation), and state explicitly which failure mode you are choosing for each class of query.

## The underlying tension A cost-based optimizer re-derives a plan from current statistics on every compile. That is precisely why it is good: as the data grows, skews, or shifts, the plan follows. It is also precisely why it is dangerous: the same SQL that ran one way yesterday can be compiled differently today, and if the new plan is worse the change looks like a spontaneous production incident. Nobody deployed anything; the optimizer simply changed its mind. So you are choosing between two failure modes: - **Adaptive**: usually right, occasionally catastrophically wrong without warning, with no change-management event to point at. - **Pinned**: predictable, and predictably wrong later, since a plan chosen for a 10-million-row table is not necessarily right at 500 million. Neither is a universal answer. The engineering question is how to allocate the risk. ## Segment the workload first Not all queries deserve the same policy. - **Critical path, tight latency budget, high volume** — a login lookup, a payment authorization, an order write path. A plan flip here is an outage. Small in number, high in value; these are pin candidates. - **Bulk and reporting** — long-running, tolerant of a 2× swing, run at low concurrency. Let the optimizer adapt; a regression is a slow night, not an incident. - **Ad hoc and exploratory** — unknowable shapes; pinning is meaningless. Protect the system with resource controls and timeouts instead. The useful rule: pin where **variance** is the problem, not where latency is merely high. If a query is slow but consistently slow, pinning does nothing for you. ## What the mechanisms actually do Different tools have different semantics, and conflating them is a common mistake: - **Hints** embedded in the SQL constrain the optimizer's choices. Some are directives that remove options entirely; others are advisory. They live in application code, so changing them means a deployment — and they silently become wrong as the schema evolves. - **Plan baselines / plan guides / forced plans** live in the database and attach to a statement identity, so they can be added and removed without touching code. Some implementations *force* one specific plan; others accept a set of approved plans and let the optimizer choose among them, which is a materially better property because it bounds the search space rather than freezing a single outcome. - **Query-store style forcing** adds the operationally important piece: automatic detection of a regression, forcing of the previously good plan, and in some engines automatic un-forcing if the forced plan stops being valid or stops helping. - **Optimizer feedback / adaptive execution** goes the other way: instead of freezing plans, the engine learns from observed cardinalities and corrects subsequent compiles, or switches operators mid-flight. Where available this addresses the cause rather than the symptom and is the preferred direction of travel. A property worth asking about every mechanism: **what happens if the pinned plan becomes impossible** — an index dropped, a partition scheme changed. Silent fallback to whatever the optimizer picks means your protection evaporated without a signal. ## Detection beats pinning The highest-leverage investment is not pinning at all — it is making plan change **observable**: - Record the plan identifier alongside query duration percentiles. Then "p99 tripled at 14:20 and the plan hash changed at 14:19" is a five-minute diagnosis instead of a day. - Alert on plan-hash churn for the critical query set specifically. - Keep enough plan history to answer "what did it used to do", so reverting is possible. With that, most teams need very few pins, because they can catch and correct a regression quickly. Without it, teams over-pin defensively — because a regression they cannot see is a regression they cannot fix. ## What pinning costs 1. **Staleness.** A frozen plan is optimal for the data at the moment it was frozen. Data grows and skews; the pin does not. 2. **Upgrade friction.** Engine upgrades change cost models and add operators. Every pin must be revalidated, and a pin that references a plan the new version cannot produce may silently lapse. 3. **Hidden defects.** A pin usually exists because an estimate was wrong. Pinning treats the symptom, so the underlying correlated columns or unestimable predicate stay broken and cause the *next* problem elsewhere. 4. **Debt accumulation.** Pins are added under pressure at 3am and never removed. After two years nobody knows which are still needed or why, and removing one becomes scary. 5. **Foreclosed improvements.** New indexes, better statistics, and new optimizer features cannot help a query whose plan is frozen. Hence the governance rule: every pin carries an **owner, a reason, a review date, and a defined test for removing it**. A pin without an expiry is technical debt with a database attached. ## The policy in one paragraph Default to adaptivity; invest first in detecting plan change and in fixing the estimation defects (statistics maintenance, multi-column statistics on correlated sets, estimable predicates) that cause bad plans in the first place. Pin a small, explicitly enumerated set of critical-path queries where variance itself is the risk, using a mechanism that bounds rather than freezes where available, and manage those pins as reviewed, expiring artifacts. Revalidate them all at engine upgrades. Measure whether the pinned plan is still the best plan periodically, and delete pins that no longer earn their place.

  • What would you build before pinning a single plan?
    Plan-change observability. Record each query's plan identifier along with duration percentiles, retain plan history, and alert when the plan hash changes for the critical query set. That converts an invisible optimizer decision into a change event you can correlate with a latency shift, which usually removes the need for most pins because regressions can be caught and reverted quickly.
  • How does a pinned-plan policy interact with database engine upgrades?
    Every pin becomes an upgrade task. New versions change cost models, add operators, and alter plan representations, so a forced plan may no longer be reproducible and can silently lapse back to optimizer choice — losing the protection without a signal. The safe pattern is to inventory pins before the upgrade, replay the critical query set on the new version, and re-decide each pin on the new engine rather than carrying them forward untested.

Pinning a plan is like taping a thermostat to a fixed setting because it once overheated: the room stays exactly as comfortable as it was that day, and nobody notices when the seasons change.

saying these in an interview costs you the question

  • Treating hints and plan baselines as interchangeable when their semantics — directive versus advisory, force one plan versus bound the set — differ
  • Pinning broadly "for safety", which guarantees today's plans against tomorrow's data
  • Pinning a query that is consistently slow rather than one whose performance is variable
  • Assuming a pinned plan survives an engine upgrade or an index change without revalidation
  • Using a pin as the permanent fix and never repairing the estimation defect that caused the bad plan

context