skip to content

questions

6

Relational database optimizers are commonly described as either rule-based or cost-based. Explain the difference, and why essentially every modern relational engine chose the cost-based design.

level: juniorimportance: must knowfreq 52%

answer

  1. Rule-based: fixed priority list, blind to data
  2. Cost-based: enumerate → estimate cardinality → cost → pick cheapest
  3. System R, 1979
  4. Selectivity decides index vs scan — only cost can see it
  5. Price of cost-based: estimation error + plan instability

basics

~20 s

A rule-based optimizer applies a fixed priority list of heuristics regardless of the data. A cost-based optimizer enumerates alternative plans, estimates the cost of each from statistics about the data, and picks the cheapest. Cost-based wins because the right plan depends on data distribution, which rules cannot see.

solid answer

~60 s

A **rule-based optimizer** transforms a query using a fixed ranking of heuristics — "prefer an index over a full scan", "drive from this table first" — with no knowledge of how much data is involved. Its output is deterministic and predictable, and it is wrong whenever the data contradicts the ranking: using an index to fetch 80% of a table is far slower than scanning it. A **cost-based optimizer** works in three parts: enumerate candidate plans (access paths, join orders, join and grouping algorithms); estimate each plan's **cardinality** — how many rows flow between operators — from statistics; and convert those cardinalities into an abstract **cost** using a model of I/O and CPU. The cheapest plan wins. Modern engines are cost-based because the correct plan genuinely depends on the data: on selectivity, on table sizes, on how much is cached. Rules cannot express "this predicate matches 3 rows here and 3 million there". The trade-off is that cost-based plans are only as good as their estimates, and they can change under you when statistics or parameters change — hence plan instability, and features like hints and plan baselines to pin behaviour.

go deeper

for a junior

State the core contrast — fixed heuristics versus estimating and comparing plan costs from data statistics — and give the index-versus-scan example.

for a middle

Break the cost-based optimizer into enumeration, cardinality estimation, and the cost model, and note that cost is an internal comparison unit.

for a senior

Emphasize that estimation error, not the cost formula, causes most bad plans, and discuss plan stability tooling and when pinning a plan is justified.

for a principal

Frame the trade as adaptivity versus predictability — cost-based buys data-dependent plans at the price of plan volatility — and describe the governance needed: statistics maintenance, regression detection, and a policy for pinned plans.

## What an optimizer is doing A SQL query says *what* result you want, never *how* to produce it. Between parsing and execution, the optimizer must choose a physical plan: which access path reaches each table (full scan, index scan, index seek plus row lookup), which algorithm implements each join, in what order tables are joined, and how grouping and sorting are performed. For a query joining six tables there are millions of valid plans whose runtimes differ by orders of magnitude. Choosing among them is the optimizer's whole job. ## Rule-based optimization The original approach — Oracle's RBO is the canonical example, and it was still in use into the 1990s — ranks access paths and transformations in a fixed priority list. A simplified version: single-row lookup by ROWID beats a unique index lookup, which beats a non-unique index range scan, which beats a full table scan; join order follows the order tables appear in the query text. Properties: - **Deterministic.** The same SQL always yields the same plan. No statistics, so no surprise regression after a statistics refresh. - **Cheap to compile.** No enumeration, no estimation. - **Blind to data.** This is the fatal defect. "Prefer the index" is right for a predicate matching 5 rows out of 10 million and badly wrong for one matching 8 million, where the index path means millions of random row fetches while a sequential scan reads the table efficiently. A rule-based optimizer cannot tell those apart, because the distinguishing fact — selectivity — lives in the data, not the query text. - **Syntax-sensitive.** Because join order follows the text, rewriting the FROM clause changes performance, which is a terrible property for maintainable SQL. ## Cost-based optimization System R (IBM, 1979) established the design every mainstream engine still uses. Three components: **1. Plan enumeration.** Generate candidate plans by applying algebraic equivalences (predicate pushdown, join commutativity and associativity, subquery flattening) and by choosing physical operators. The space is exponential, so the search is pruned — dynamic programming over join orders, interesting-order tracking, and heuristic or randomized search once the table count is large. **2. Cardinality estimation.** For each intermediate result, estimate how many rows it produces, starting from stored statistics (row counts, distinct-value counts, histograms, null fractions) and applying selectivity formulas per predicate. This is the part that decides plan quality. **3. Cost model.** Turn estimated cardinalities and access patterns into a number: pages read (distinguishing sequential from random), rows and comparisons processed, memory required. The unit is arbitrary and internal — it is a *comparator*, not a prediction of milliseconds. The cheapest plan is executed. ## Why cost-based won Because the right answer is data-dependent, and only a cost model can express that. The same query against a 1,000-row table and a 1-billion-row table deserves different plans. The same predicate deserves an index seek for a rare value and a scan for a common one. A cost-based optimizer also lets the engine add new physical operators — hash join, bitmap access, parallel execution — and have them chosen automatically wherever they win, instead of demanding a new rule and a new priority position. ## What it costs you - **Estimates can be wrong.** The optimizer optimizes its *belief* about the data. A cardinality estimate off by 1000× yields a plan that is optimal for a world that does not exist. Most catastrophic plans trace to estimation error, not to the cost formula. - **Plans change under you.** New statistics, changed data, a different parameter value, or an engine upgrade can flip a plan. When the flip goes the wrong way it looks like a spontaneous outage. This drove the whole ecosystem of hints, plan baselines, plan guides, and forced plans. - **Compilation is not free.** Enumeration costs CPU, which is why engines cache plans and why plan-cache behaviour (and parameter-sensitive plans) becomes its own topic. - **The model is a simplification.** Cost formulas assume things — a fixed sequential-to-random I/O ratio, an assumed cache-hit fraction, independent predicates — that are approximations of a real machine. ## The nuance worth stating "Cost-based" does not mean rule-free. Every real optimizer still applies heuristic rewrites unconditionally when they are always-or-almost-always beneficial — pushing predicates below joins, eliminating provably empty branches, flattening simple subqueries — because costing them out would waste compile time. The accurate description is that modern optimizers are **cost-based with a heuristic rewrite layer**, and the cost model decides only where the answer genuinely depends on data.

  • Give a concrete case where the rule "always prefer an index over a full table scan" is badly wrong.
    A predicate matching a large fraction of a heap table. Reaching 8 million of 10 million rows through a non-covering index means walking the index and then doing millions of largely random row fetches, often revisiting the same page many times. A sequential scan reads each page once in physical order with readahead, so it can be an order of magnitude faster. The crossover typically arrives at a fairly low selectivity — often single-digit percentages — precisely because of the random-versus-sequential I/O difference.
  • If cost-based optimization is better, why do engines still ship hints, plan baselines, and forced plans?
    Because a cost-based plan is only as good as its cardinality estimates, and estimates fail on correlated columns, opaque predicates, and skewed parameters. Those mechanisms let an operator pin a known-good plan when the optimizer's belief about the data is systematically wrong. They are a stability tool of last resort: they freeze the plan, so they also freeze out improvements as the data changes, and they need review whenever data or the engine version shifts.

Rule-based is a driver who always takes the highway; cost-based is a navigation app that checks live traffic. The app is usually better, and it is spectacularly wrong when its traffic data is stale.

saying these in an interview costs you the question

  • Believing cost is measured in milliseconds rather than in arbitrary internal units used only for comparison
  • Claiming modern optimizers use no heuristics at all — unconditional rewrites still exist alongside costing
  • Saying a cost-based optimizer picks the fastest plan, rather than the cheapest plan under its estimates
  • Assuming an index is always preferable to a scan regardless of selectivity
  • Thinking join order is determined by the order tables appear in the query text in a cost-based engine

context

open as a page

Explain what selectivity and cardinality mean to a query optimizer, how a predicate's selectivity is turned into an estimated row count, and why an error in an early estimate is more damaging than an error in the cost formula.

level: middleimportance: must knowfreq 58%

basics

~20 s

Selectivity is the fraction of rows a predicate keeps (0 to 1); cardinality is the resulting row count — input rows times selectivity. Every cost term scales with cardinality, and estimates feed into the next operator, so an early error multiplies up the plan tree and produces structurally wrong join and access choices.

open as a page

Optimizers typically estimate the combined selectivity of two AND-ed predicates by multiplying their individual selectivities. Explain the assumption behind that, describe a realistic case where it fails badly, and how you would address it.

level: seniorimportance: must knowfreq 50%

basics

~20 s

It assumes the columns are statistically independent. When they are correlated — a city implies its state, a model implies its manufacturer — multiplying selectivities counts the same restriction twice and severely under-estimates rows. Fix with multi-column statistics, a materialized combined column, or a schema change that removes the redundancy.

open as a page

A query optimizer assigns each candidate plan a numeric cost. What goes into that number, why do engines separate sequential from random page access in the formula, and what does the number actually mean?

level: middleimportance: should knowfreq 42%

basics

~20 s

Cost combines estimated I/O (pages touched, weighted differently for sequential versus random access) with CPU terms (per row processed, per predicate evaluated, per index entry). The result is an abstract unit for comparing plans on the same query, not a time prediction. Random access is weighted higher because scattered reads lose readahead and locality.

open as a page

A query that normally runs in under a second occasionally takes minutes, with no schema or code change. How would you determine whether the optimizer's estimates or its cost model are to blame, and what are the common sources of such estimate failures?

level: seniorimportance: should knowfreq 45%

basics

~20 s

Capture the executed plan with actual row counts and compare them to the estimates operator by operator, bottom-up. The lowest node where estimated and actual diverge sharply is the cause. Common sources: stale statistics, correlated predicates, parameter-sensitive plans, opaque predicates, and values beyond the histogram's range.

open as a page

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%

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.

open as a page