Covering Index
A covering index contains every column a query needs, allowing the database to answer the query from the index without fetching the corresponding base-table rows. This can reduce I/O and improve read performance, especially for selective queries and workloads where the index remains relatively small.
A normal index stores indexed key values plus enough information to locate the underlying row. If a query needs columns that are not present in that index, the database may perform an additional lookup into the table or clustered index to retrieve them.
A covering index includes all columns required by the query, including columns used for filtering, joining, sorting, or returned in the result. When the optimizer chooses it, the database can obtain the required data directly from the index, avoiding those extra row lookups.
For example, consider `SELECT name, email FROM users WHERE status = 'ACTIVE'`. An index such as `(status, name, email)` can cover this query because both the predicate and projected columns are available in the index. The exact storage and execution behavior depends on the database engine and index type.
Covering indexes can improve read performance by reducing random I/O, but they are not free. Adding more columns increases index size and can increase the cost of `INSERT`, `UPDATE`, and `DELETE` operations because the index must also be maintained. The best design therefore balances query performance against storage and write overhead.
In an interview, distinguish the logical property of coverage from the execution plan. An index may be capable of covering a query, but the optimizer can still choose another access path if it estimates that path to be cheaper.
Key points
- A covering index contains all columns required to execute a query.
- It can eliminate lookups from the index into the base table or clustered index.
- Coverage can reduce I/O and improve read-heavy query performance.
- Wider indexes consume more storage and increase write-maintenance cost.
- Use the execution plan to verify whether the optimizer actually uses an index-only access path.
Interview questions
What is a covering index, and why can it improve query performance?
A covering index contains every column needed by a particular query. If the database can obtain the predicate and result columns directly from the index, it does not need an additional lookup for the base table row. That can reduce I/O and improve latency. The trade-off is that wider indexes require more storage and maintenance.
Given `SELECT name, email FROM users WHERE status = 'ACTIVE'`, what index could cover it?
An index containing `status`, `name`, and `email` could cover this query. For example, depending on the database engine, an index with `status` as the key and `name` and `email` as additional stored index columns could provide all required data. The exact definition differs between database systems because not every engine supports included columns in the same way. I would confirm the design with the actual execution plan and workload.
Does a covering index guarantee an index-only scan?
No. Coverage means the index contains the information required by the query, but it does not force the optimizer to choose that access path. The optimizer estimates the cost of available plans using factors such as selectivity, statistics, and expected I/O. It may choose a table or clustered-index scan if that is estimated to be cheaper.
What are the trade-offs of creating a covering index?
The main benefit is reduced read I/O because the query can sometimes be answered entirely from the index. The main costs are additional storage, larger indexes, longer maintenance work during writes, and potentially more cache pressure. A covering index should therefore target an important query rather than simply include every frequently selected column. I would validate the benefit with production-like workload measurements and execution plans.