Chapter 14 · Indexes and Query Execution
Sargability, Statistics, and Cardinality Estimation
An available index is useful only when the optimizer can map a predicate to its ordered keys and estimate the result size credibly. Sargability and statistics connect SQL text to plan quality.
Learning outcomes
Make predicates searchable and estimates credible
Define sargability as the optimizer’s ability to map a predicate to an ordered search argument.
Rewrite function-wrapped, cast-heavy, and pattern predicates into index-friendly forms.
Use expression indexes when the transformation is a stable part of the workload.
Explain how selectivity and cardinality estimates influence plan choice.
Refresh and inspect SQLite statistics with ANALYZE and reason about correlated columns.
Sargability connects SQL to index order
A predicate is commonly called sargable when it exposes a search argument that an index can navigate. The database needs a relationship such as indexed_key = constant, a bounded range, or a compatible prefix—not an opaque transformation that must be computed for every row.
A syntactically valid predicate can still hide the ordered key from the optimizer.
Date filtering: half-open ranges beat wrapped columns
CREATE INDEX idx_order_dateON sales_order (ordered_at);SELECT COUNT(*)FROM sales_orderWHERE strftime('%Y-%m', ordered_at) = '2025-06';SELECT COUNT(*)FROM sales_orderWHERE ordered_at >= '2025-06-01' AND ordered_at < '2025-07-01';The half-open range preserves the raw indexed value and handles timestamps throughout the final day without fragile “23:59:59” boundaries.
Use an expression index when the expression is the contract
CREATE INDEX idx_customer_email_lowerON customer (lower(email));SELECT customer_id, emailFROM customerWHERE lower(email) = lower('Customer0417@Example.com');Expression indexes are appropriate when the transformation is deterministic, frequent, and standardized. They are not a reason to index every ad hoc function users might write.
Pattern matching and prefixes
| Predicate shape | Typical B-tree opportunity |
|---|---|
| email = 'customer0417@example.com' | Exact seek. |
| email >= 'customer04' AND email < 'customer05' | Explicit prefix range. |
| email LIKE 'customer04%' | May use a compatible text index depending on collation and LIKE settings. |
| email LIKE '%0417%' | Leading wildcard usually prevents a narrow ordered seek. |
| lower(email) = ... | Needs a matching expression index or normalized stored column. |
CREATE INDEX idx_customer_emailON customer (email);SELECT customer_id, emailFROM customerWHERE email >= 'customer04' AND email < 'customer05'ORDER BY email;Implicit conversions and type alignment
Column type: INTEGERParameter type: integer, not textColumn expression: unchanged when possibleCollation: matches indexed collationTimezone boundary: converted once before queryPattern: anchored unless substring search is intentionalDatabase products differ in coercion rules, but the safe principle is stable: compare compatible types and collations. Convert the parameter once rather than wrapping the indexed column for every row.
Cardinality is estimated row count
If a relation has N rows and the optimizer estimates predicate selectivity s, the estimated output cardinality is:
Plan decisions depend on this estimate: nested loop versus hash join, index lookup versus scan, sort memory, parallelism, and join order.
| Estimate input | What it approximates |
|---|---|
| Row count and page count | Base relation size. |
| Distinct-value count | Equality selectivity. |
| Most-common values | Skewed hot values that differ from uniform assumptions. |
| Histogram boundaries | Range selectivity. |
| Null fraction | IS NULL and general distribution. |
| Extended or multicolumn statistics | Dependencies and correlations between columns. |
Refresh SQLite statistics
CREATE INDEX IF NOT EXISTS idx_order_customer_dateON sales_order (customer_id, ordered_at);CREATE INDEX idx_order_status_dateON sales_order (status, ordered_at);ANALYZE;SELECT tbl, idx, statFROM sqlite_stat1WHERE tbl IN ('customer', 'sales_order')ORDER BY tbl, idx;ANALYZE records statistics that help SQLite compare candidate plans. Statistics should represent production-like data; a tiny empty test database teaches the optimizer very little about the real workload.
Correlation breaks naive independence
Suppose region and channel are correlated. A simple estimator may multiply selectivities:
If mobile orders are concentrated in one region, the true joint selectivity can differ substantially. PostgreSQL extended statistics can model dependencies and multivariate distributions; SQLite’s statistics model is simpler, so schema, indexes, and query shape deserve careful testing.
Prove the rewrite with plans
EXPLAIN QUERY PLANSELECT order_idFROM sales_orderWHERE strftime('%Y-%m', ordered_at) = '2025-06';EXPLAIN QUERY PLANSELECT order_idFROM sales_orderWHERE ordered_at >= '2025-06-01' AND ordered_at < '2025-07-01';The second form should expose a bounded range on idx_order_date. The first can use an expression index only if one was explicitly created for the same expression.
Checkpoint
Repair the predicate
- Why is strftime applied to every stored timestamp often less index-friendly than a date range?
- When is an expression index justified?
- Why does a leading wildcard usually defeat a narrow B-tree seek?
- What is the relationship between selectivity and estimated cardinality?
- How can correlated columns cause a poor plan even when single-column statistics are accurate?
Review the answers
The wrapped form hides the raw ordered key, while a range directly bounds it. An expression index is justified for a deterministic, repeated transformation. A leading wildcard provides no known starting prefix. Estimated cardinality equals base rows times estimated selectivity. Multiplying independent single-column estimates can be badly wrong when values co-occur non-independently.
Summary and references
- Sargable predicates expose ordered keys and compatible operators.
- Half-open ranges are robust for timestamp intervals.
- Expression indexes support standardized deterministic transformations.
- Statistics drive selectivity and cardinality estimates.
- Validate rewrites with plans and representative data.