Definition
A sequential scan (Seq Scan in PostgreSQL EXPLAIN output) reads every heap page of a table in physical order, applying the query’s filter predicates to each row. It requires no index and has no startup cost. Its total cost scales linearly with table size.
The query planner chooses Seq Scan when it estimates that the query will return a large fraction of the table (low selectivity), when the table is small enough that index overhead would cost more than the scan, or when no useful index exists. The planner’s estimate is based on statistics from the most recent ANALYZE.
A Seq Scan is not always wrong. On a table with 1,000 rows, a Seq Scan is often faster than an Index Scan because it avoids tree traversal overhead. On a table with 10 million rows, a Seq Scan for a query selecting 0.01% of rows is a problem.
Unexpected Seq Scans usually mean stale statistics (run ANALYZE), a non-matching index (wrong column order, wrong operator class), or a type mismatch in the WHERE clause that prevents index use.
When it applies
Set enable_seqscan = off temporarily in a session to force the planner to use indexes and confirm an index would help. Never set this globally. Use pg_stat_user_tables.seq_scan and seq_tup_read to identify tables with excessive sequential scans in production.
Example
SELECT relname, seq_scan, seq_tup_read, idx_scan
FROM pg_stat_user_tables
ORDER BY seq_scan DESC
LIMIT 10;
SET enable_seqscan = off;
EXPLAIN SELECT * FROM events WHERE user_id = 42;
RESET enable_seqscan;Related concepts
- query-plan - the planner chooses between sequential scan and index scan based on cost estimates.
- btree-index - the primary way to eliminate unnecessary sequential scans.
- gin-index - replaces sequential full-text and JSONB scans.
- vacuum - VACUUM updates the visibility map and reduces unnecessary heap fetches.
- postgres-explain - reference for reading Seq Scan cost estimates.
Citing this term
See Sequential Scan (llmbestpractices.com/glossary/sequential-scan).