Hello! Welcome to the next lesson in our module on Query Optimization.
In our previous lesson, we explored how a query optimizer uses logical transformations like predicate pushdown and join reordering. These rule-based heuristics are powerful, but they can only take us so far. To choose between two different valid join orders, like (A ⋈ B) ⋈ C versus A ⋈ (B ⋈ C), the optimizer needs to quantitatively compare them. It needs to ask: which plan is cheaper to execute?
This brings us to the focus of today's lesson: cost-based optimization. Specifically, we'll tackle the most fundamental input to any cost model. Your learning outcome for this session is to estimate the cardinality of query results using statistics and selectivity. Understanding this is the key to unlocking how a modern database makes intelligent decisions about executing your queries.
The Cost-Based Optimization Framework
Before we can choose the "best" plan, we need a way to define what "best" means. Database systems use a cost model to assign a numerical score to a physical query plan. This cost is an estimate of the resources required for execution, primarily driven by I/O, but also considering CPU, memory, and network usage.
A critical input to this cost model is the estimated number of rows, or cardinality, that flows through each operator in the plan. After all, the cost of joining two tables depends heavily on how many rows are in each one.
The query optimizer's job is to explore the space of possible plans, estimate the cost of each one using cardinality estimates, and pick the one with the lowest cost.

This process, however, is notoriously difficult. The optimizer can't run parts of the query to get exact counts, as that would be too slow. It must rely on estimates, and errors in these estimates can cascade up the query plan, leading to poor plan choices.
#15 - Query Planning & Optimization (CMU Intro to Database Systems)
Let's watch a clip from a CMU lecture that introduces the concept of cost-based search and the inherent difficulty of cost estimation.
Please watch from 26:31 to 27:46, and then from 1:03:56 to 1:07:00. Pay attention to: The distinction between rule-based rewriting and cost-based search. The components of a cost model (physical and logical costs). The "house of cards" problem: how small estimation errors at the bottom of a plan can lead to huge errors at the top.
The Foundation: Database Statistics
As you just heard, the optimizer's estimates are based on statistical information about the data. The DBMS collects and stores these statistics in its internal catalog. This process is often triggered automatically when data changes significantly, or it can be manually invoked by a DBA using a command like ANALYZE or UPDATE STATISTICS.
For any given relation R, the catalog typically stores:
|R|: The total number of tuples (rows) in the relation.s(R): The average size of a tuple in bytes.- For each attribute
AinR:V(A, R): The number of distinct values of attributeA.Low(A, R)andHigh(A, R): The minimum and maximum values of attributeA.
These simple statistics are the building blocks for everything that follows.
Estimating Cardinality with Selectivity
To estimate the cardinality of an operation like σ_p(R), the optimizer calculates the selectivity of the predicate p, denoted sel(p).
Selectivity is the fraction of tuples that are expected to satisfy a predicate.
The estimated cardinality of the selection is then simply:
The challenge lies in calculating sel(p). For this, the optimizer uses a set of formulas that rely on the catalog statistics and two major, simplifying assumptions:
- Uniform Distribution: The values of an attribute are spread evenly across their range.
- Predicate Independence: The values of different attributes are not correlated with each other.
Let's see how this works in practice.
CMU Database Systems - 13 Query Optimization (Fall 2018)
The following segment from another CMU lecture provides an excellent walkthrough of the core selectivity formulas. The concepts here are fundamental to all query optimizers.
Please watch from 41:25 to 53:00. This is a dense but very important section. As you watch, focus on understanding the formula for each type of predicate: How basic statistics (|R| and V(A,R)) are collected and used. Equality Predicate (A = c): How selectivity is derived from the number of distinct values. Range Predicate (A >= c): How selectivity is estimated using the min and max values. Negation (A != c): How this is derived from the equality case. Conjunction (p1 AND p2): The multiplication rule and the crucial (and often flawed) independence assumption. Disjunction (p1 OR p2): The addition rule for probabilities.
Summary of Selectivity Formulas
To solidify what you just watched, here is a summary of the core formulas. This reference material from the University of Antwerp is a great, concise guide.
These slides formally define the selectivity formulas we need. They serve as a great reference sheet.
Please read slides 4 through 10 (PDF pages 4-6). Focus on the formulas for: Equality Predicate (A = c): sel = 1 / V(A, R) Range Selection (A > c): sel = (High(A, R) - c) / (High(A, R) - Low(A, R)) Also, review slide 8, which explains the uniformity and independence assumptions.
The independence assumption is particularly important from an engineering perspective. As the video noted with the make='Honda' and model='Accord' example, attributes are often correlated. Assuming they are independent can lead the optimizer to grossly underestimate the selectivity and make a poor plan choice. Modern commercial databases have ways to detect and store statistics on correlated columns, but it adds significant complexity.
Test your understanding!
You have a Products table with 2,000,000 rows. The database catalog contains the following statistics:
|Products|= 2,000,000V(category, Products)= 100 (distinct categories)Low(price, Products)= 1.00High(price, Products)= 1000.00V(status, Products)= 4 (distinct statuses: 'active', 'discontinued', 'backorder', 'archived')
Estimate the number of rows returned by the following query, assuming uniform distribution and predicate independence. Show your steps.
SELECT * FROM Products
WHERE category = 'electronics' AND price > 800;
Show answer
Here is the step-by-step estimation:
-
Break down the predicate into two parts:
p1:category = 'electronics'p2:price > 800
-
Calculate selectivity of
p1(Equality):sel(p1) = 1 / V(category, Products) = 1 / 100 = 0.01
-
Calculate selectivity of
p2(Range):sel(p2) = (High(price) - 800) / (High(price) - Low(price))sel(p2) = (1000.00 - 800.00) / (1000.00 - 1.00) = 200 / 999 ≈ 0.2002
-
Calculate combined selectivity (Conjunction):
- Since the predicates are
ANDed together, we assume independence and multiply their selectivities. sel(p1 AND p2) = sel(p1) * sel(p2) ≈ 0.01 * 0.2002 = 0.002002
- Since the predicates are
-
Estimate the final cardinality:
Estimated Rows = sel(combined) * |Products|Estimated Rows ≈ 0.002002 * 2,000,000 = 4004
The optimizer would estimate that this query will return approximately 4004 rows. This number would then be used to calculate the cost of subsequent operations in the query plan.
Dealing with Reality: The Problem of Skew
The uniformity assumption simplifies calculations, but real-world data is rarely uniform. It's often skewed, with some values appearing much more frequently than others. Using a simple formula like 1 / V(A, R) would be highly inaccurate in such cases.
To handle skew, optimizers use histograms. A histogram is a data structure that approximates the distribution of values in a column by grouping them into buckets. Instead of assuming every value is equally likely, the optimizer can look up a value in the histogram to get a much better estimate of its frequency.
CMU Database Systems - 13 Query Optimization (Fall 2018)
Let's return to the CMU lecture to see how histograms solve the problem of data skew and how the two most common types—equi-width and equi-depth—work.
Please watch from 57:57 to 1:05:02. This segment provides a great visual intuition for histograms. Notice how real data distributions are often skewed. Understand the basic idea of an equi-width histogram (fixed bucket width). Understand how an equi-depth histogram adapts to skew by using variable-width buckets to ensure each bucket has roughly the same number of items.
Histograms represent a classic engineering trade-off: they consume more memory in the catalog and take time to compute, but they drastically improve the accuracy of cardinality estimates, leading to better query plans.
Conclusion
Today you've taken a crucial step into the world of cost-based optimization. You've learned how optimizers predict the size of data flowing through a query plan, a process that is part science and part art.
Key Takeaways:
- Cardinality estimation is the process of predicting the number of rows an operator will return, which is a fundamental input for cost-based optimization.
- Estimates are based on statistics (like tuple counts and distinct value counts) stored in the database's catalog.
- Selectivity is the fraction of tuples that a predicate will match. Simple formulas exist for common predicates, but they rely on assumptions of uniform distribution and predicate independence.
- These assumptions are often violated by real-world data, which can lead to large estimation errors.
- Histograms are a key technique to combat data skew by storing a more detailed approximation of the data's distribution.
Preview of the Next Lesson
We've just scratched the surface of histograms. They are so critical to modern optimizers that they deserve their own lesson. In our next session, we will dive deeper, addressing the learning outcome: Describe how equi-width and equi-depth histograms are used to estimate predicate selectivity. We will look at their data structures, how they are constructed, and precisely how they are used to calculate more accurate selectivity for both equality and range predicates.