Skip to content
All articles
Articlepostgresperformanceexplain

Reading Postgres EXPLAIN ANALYZE: The 2026 Guide

A field guide to Postgres EXPLAIN ANALYZE in 2026. The operators that matter, the numbers to look at, and the four patterns that explain 90% of slow queries.

12 min read

EXPLAIN ANALYZE is the single most useful Postgres tool, and the one most teams use timidly. Past 2024 the output format settled, the operators got fully documented, and AI assistants can read the trees for you. In 2026 it's the obvious starting point when anything is slow.

The shape of an EXPLAIN output

Every plan is a tree of nodes. Each node has a type (Seq Scan, Index Scan, Hash Join, etc.), an estimated cost, an actual time, and an actual row count.

explain-example.sqlsql
EXPLAIN (ANALYZE, BUFFERS, VERBOSE)
SELECT u.id, u.email, count(p.id) AS post_count
FROM users u
LEFT JOIN posts p ON p.author_id = u.id
WHERE u.created_at > now() - interval '7 days'
GROUP BY u.id, u.email
ORDER BY post_count DESC
LIMIT 10;

Read the tree bottom-up. Each node feeds its parent. The interesting nodes are usually the leaves and the joins.

Operators that matter

  • Seq Scan: reads every row in a table. Fine on small tables, a problem on big ones. If you see this on a table over a few thousand rows in a hot query, you need an index.
  • Index Scan: uses an index. Fast. Good.
  • Index Only Scan: uses an index AND doesn't need to fetch the heap. Even better. Requires every column referenced to be in the index (covering index).
  • Bitmap Heap Scan: uses an index but in a different way; Postgres builds a bitmap of matching pages then reads them. Common when several conditions can use indexes that combine via AND/OR.
  • Nested Loop: joins by iterating one side and looking up the other. Fast for small driving tables. Catastrophic for big ones.
  • Hash Join: builds a hash on one side, scans the other. Good for big-to-big.
  • Merge Join: requires both sides sorted. Cheap if you happen to have indexes that sort the right way; otherwise the sort step adds time.
  • Sort: ordering rows. Expensive if it doesn't fit in work_mem (you'll see "external merge Disk" in the plan).

Numbers that lie

The trap most beginners fall into: the planner's cost estimate.

Cost is a unitless number Postgres uses internally to pick the cheapest plan. It's not seconds, not microseconds. It correlates loosely with reality. Don't compare costs across queries; only within a single query's alternatives.

What actually matters: actual time, rows (compare estimated vs actual: if they're wildly different, your statistics are stale), and loops (a node with loops=1000 ran 1000 times, even if each ran fast).

Four patterns that explain 90% of slow queries

1. Seq Scan on a big table

Missing index. Add one on the column(s) in the WHERE clause. For composite predicates, the order matters: the most selective column first.

2. Nested Loop with huge outer rows

The planner expected a small driving table; it got a big one. Either the statistics are stale (run ANALYZE) or you need a different join strategy. Add an index on the inner table's join column.

3. Sort spilling to disk

work_mem is too small for the sort. Either increase it for that session, or arrange to use a presorted index, or limit the result set before sorting.

4. Estimated vs actual rows wildly different

Stale statistics. Run ANALYZE table_name. If it persists, look at default_statistics_target for that column or add multi-column statistics with CREATE STATISTICS.

BUFFERS is your friend

Add BUFFERS to your EXPLAIN ANALYZE. It tells you how many 8KB pages the query read from cache vs disk. A query that reads 1M buffers is doing a lot of I/O regardless of how cleverly the plan looks.

sql
EXPLAIN (ANALYZE, BUFFERS) SELECT ...

shared hit means cached; shared read means from disk; shared dirtied means a write happened in the query. The ratio of hit to read tells you whether you have a memory problem or a query problem.

Once you can read EXPLAIN ANALYZE fluently, you can fix most performance problems in minutes instead of hours. For the bigger picture of when to add what, see our indexes guide.

Suparbase is an admin workspace for Supabase. Encrypted credentials, server-side proxy, RLS debugger, SQL playground, AI assistant with diff-confirmed writes. Free tier for solo projects.

Related articles