Chapter 11 · Index-Aware Logical and Physical Design
Covering, Partial, and Specialized Indexes
Use covering, partial, expression, and specialized indexes appropriately, understanding what each technique optimizes and what tradeoffs it introduces.
Learning outcomes
Ordinary B-tree indexes are only the beginning. Production databases often use covering indexes, partial indexes, expression indexes, and engine-specific specialized index types to align physical access structures with particular workloads. These techniques can be powerful, but each should solve a concrete problem.
Use covering indexes to reduce table lookups for narrow hot queries.
Use partial indexes to target small operational subsets.
Use expression indexes when predicates depend on computed expressions.
Recognize when full-text, spatial, JSON, or other specialized indexes are appropriate.
Covering index concept
An index “covers” a query when the engine can satisfy required predicates and selected columns from the index alone, avoiding or reducing visits to the base table.
Example
SELECT opened_at, status_codeFROM work_orderWHERE asset_id = ?ORDER BY opened_at DESCLIMIT 20;An index containing:
asset_id, opened_at, status_codemay allow an index-only plan under suitable engine/visibility conditions.
Key columns versus included columns
Some databases support INCLUDE columns that are stored in leaf entries but do not participate in index ordering:
CREATE INDEX ...ON work_order(asset_id, opened_at)INCLUDE (status_code);This can cover a query without widening the ordered key unnecessarily.
Covering is workload-specific
Adding every selected column to an index is usually a mistake. Cover only narrow, frequent, latency-sensitive queries where avoiding table access materially helps.
Partial indexes
A partial index stores only rows matching a predicate:
CREATE INDEX ix_work_order_openON work_order(opened_at)WHERE status_code IN ('open','blocked','scheduled');This can be much smaller than indexing all WorkOrders when active rows are a small fraction.
Partial indexes can enforce conditional uniqueness
Example concept:
one active primary assignment per work orderA unique partial index may enforce that invariant:
CREATE UNIQUE INDEX ...ON work_order_assignment(work_order_id)WHERE role_code = 'primary' AND ended_at IS NULL;Exact syntax and predicate support vary by database engine.
A specialized index can sometimes improve performance and encode a business rule at the same time.
Expression indexes
For case-insensitive lookup:
WHERE lower(email) = lower(:email)an index on:
lower(email)may align with the predicate.
Normalized forms in expression indexes
Instead of repeatedly computing normalized identifiers in application code, some systems index a canonical expression such as:
lower(trim(sku))But normalization rules should be stable and deterministic.
Full-text indexes
Searching:
WHERE description LIKE '%bearing noise%'is usually not what ordinary B-tree indexes are designed for. Full-text search indexes tokenize and rank text according to engine-specific capabilities.
Spatial indexes
Geographic queries such as “find service centers within 25 km” need spatial data types and spatial indexes rather than ordinary scalar B-tree assumptions.
JSON/document indexes
If WorkshopHub stores semi-structured diagnostic metadata in JSON, some engines support GIN/inverted or path indexes over JSON contents. Use them only when JSON is justified by the logical model and queried frequently.
Hash indexes
Some engines offer hash index structures optimized for equality. Capabilities and durability/support vary. B-tree remains the general-purpose default in many systems because it supports equality, range, and ordering.
Bitmap-like strategies
Analytical engines and warehouses may use bitmap indexes or bitmap execution techniques for low-cardinality columns. These are workload/engine-specific and can be inappropriate for high-concurrency OLTP writes.
BRIN-style indexes
Block-range indexes summarize physical ranges and can be extremely compact for naturally ordered large tables, such as append-heavy event tables by timestamp. They are less precise than B-trees but much smaller.
Clustering and index-organized storage
Some systems can physically cluster rows by an index or store the table itself in a primary-key/index-organized structure. This can improve locality for one access path but usually cannot keep the table physically clustered by many different indexes simultaneously.
Covering-index tradeoff
A wider covering index may:
- reduce table reads;
- increase storage;
- increase write amplification;
- reduce cache density;
- take longer to build/rebuild.
Partial-index tradeoff
Partial indexes are smaller and targeted but useful only when query predicates logically imply the index predicate. Query formulation matters.
WorkshopHub advanced candidates
| Need | Index pattern |
|---|---|
| Active work queue | Partial index on active statuses |
| Case-insensitive customer email | Expression index on normalized email |
| Newest orders by asset with status display | Covering composite index |
| Search problem descriptions | Full-text index |
| Large append-only audit table by time | BRIN/range-summary style index where supported |
Practice: choose the specialized index
Four needs
- Search part descriptions by words.
- Query only the 2% of WorkOrders still active.
- Lookup email case-insensitively.
- Return asset_id/opened_at/status without touching table pages.
Review answer
Full-text index; partial index; expression index; covering/index-only-oriented composite index. Exact syntax depends on the DBMS.
Summary and next lesson
Advanced index types let physical design match specialized workloads: covering indexes reduce table access, partial indexes target small subsets, expression indexes support computed predicates, and specialized structures serve text, spatial, JSON, or append-heavy data. The final lesson examines their cost over the full database lifecycle.
References
- PostgreSQL documentation on index-only scans, partial indexes, expression indexes, GIN, GiST, and BRIN.
- Markus Winand, SQL Performance Explained.
- Database engine documentation for supported specialized index types.