If a value matches a large fraction of the table, reading the index and then fetching those rows costs more than scanning. The planner knows this and skips the index you added.
CREATE INDEX idx_orders_status ON orders (status); -- 3 distinct values
SELECT * FROM orders WHERE status = 'PAID'; -- 73% of rows -> seq scan
SELECT * FROM orders WHERE status = 'REFUND'; -- 1% of rows -> index scan
-- A partial index only covers the selective value, and is far smaller:
CREATE INDEX idx_orders_refund ON orders (created_at)
WHERE status = 'REFUND';
status='PAID' -> Seq Scan (rows=7,210 of 9,876)
status='REFUND' -> Index Scan (rows=118)
-- The same index, two plans, both correct. "The index is not being used"
-- is usually the planner being right.
--
-- The partial index above is 118 entries instead of 9,876.
Run this yourself in the Online Java Compiler, spin up a live REST API in the API Sandbox, or practise with Java interview questions.
Published 2026-08-25