Contents

Backend Development › Indexing & Query Performance

Covering Index

An index containing every column a query needs.

Also known as: covering index, index-only scan, covering indexes

A covering index includes all the columns a query needs, so the database can answer it from the index alone without going back to the table. A normal index scan is two steps — find rows in the index, then fetch each row from the table; a covering index skips the second step, eliminating those random reads.

-- query
SELECT id, total FROM orders WHERE customer_id = 42;
-- covering index: customer_id (filter) + id, total (include)
CREATE INDEX ON orders (customer_id) INCLUDE (id, total);

The INCLUDE clause (or just adding the columns to a composite index) makes the index self-sufficient. Databases report this as an “index-only scan” or “covering index scan” in the query plan.

The classic mistakes:

  • Assuming any index covers. A single-column index only covers a query selecting that column plus the key. Select anything else and the database must fetch from the table — no longer covering.
  • Over-covering. Adding many columns bloats the index, slows writes and wastes space. Cover the queries that matter, not all of them.
  • Forgetting that covering still isn’t free. It avoids the table fetch, but the index itself is read and values compared; for large result fractions, a sequential scan may still win.
  • Ignoring index maintenance cost. Every index makes inserts/updates/deletes more expensive. A covering index for one query is a tax on every write — weigh it.
  • Caching the wrong query. Covering helps repeated, latency-sensitive lookups (hot reads). If the query runs rarely, the write cost likely outweighs the benefit.
  • Assuming visibility rules are free. On some MVCC databases, index-only scans still check heap visibility for recently changed rows, so the win varies with vacuum state (see VACUUM).

When to use it: for frequent, performance-critical read queries where the table fetch dominates — typically point lookups or small-range reads on hot tables. Confirm with the plan that you’ve actually achieved an index-only scan, and mind the write overhead. It’s one of the highest-value index optimisations when aimed at the right query.