Cards/DatabasesSystem Design · Day 42Sep 12, 2026

Why It Ignored Your Index

Index lookup against sequential scan for the same query, the row-count threshold where the planner switches, three ways statistics mislead it, and ANALYZE before reaching for a new index

You added the index. The query still does a sequential scan. The database did the arithmetic and decided your index was the slower option.

SQL says what you want, never how. The planner picks the how, by estimating the cost of each route and taking the cheapest. For SELECT * FROM orders WHERE customer_id = 123 there are two routes to the same rows. An index lookup fetches matching rows through the index, jumping around the disk — fast when few rows come back, expensive when they're scattered. A sequential scan reads the table straight through, page by page, and sequential reads are cheaper than thousands of random jumps.

So it depends on how many rows you need. Two percent of the table and the index wins. Forty percent and the scan wins. If the query touches most of the table anyway, reading it straight through beats the lookup, and the planner is often right.

When it gets this wrong, the statistics are usually why — stale, because ANALYZE hasn't run; an unknown distribution, where there's no histogram for the column; correlated columns the planner assumed were independent. Which is why the fix starts with ANALYZE, moves on to rewriting the query, and only then considers a new index.

When a system makes a decision you disagree with, check what it was looking at before you argue with its logic.

When a system makes a decision you disagree with, check what it was looking at before you argue with its logic.