EXPLAIN and EXPLAIN ANALYZE
Objectives
By the end of this lesson, you should be able to:
- See how PostgreSQL plans to run a query with
EXPLAIN - See a query’s actual execution with
EXPLAIN ANALYZE - Explain why PostgreSQL sometimes skips an available index
💡 Why this matters: Creating an index (previous lesson) doesn’t guarantee PostgreSQL actually uses it, the query planner decides that for each query, based on real cost estimates.
EXPLAINshows that decision directly, instead of guessing.
⚠️ A note on verification: every statement and result in this lesson was run against a real, live PostgreSQL 18 database, using the
employeestable (9 rows) from earlier lessons, withidx_employees_department(from the previous lesson) in place.
EXPLAIN
EXPLAIN SELECT * FROM employees WHERE last_name = 'Castillo';
Seq Scan on employees (cost=0.00..1.12 rows=1 width=696)
Filter: ((last_name)::text = 'Castillo'::text)
EXPLAIN shows the execution plan, what PostgreSQL intends to do, without actually running the query. Seq Scan on employees means a sequential scan, checking every row in the table one by one. cost=0.00..1.12 is an internal cost estimate (not a real time unit, just a relative number the planner uses to compare plans), rows=1 is the planner’s estimate of how many rows will match.
Why a Sequential Scan, Not the Index
EXPLAIN ANALYZE SELECT * FROM employees WHERE department = 'Engineering';
Seq Scan on employees (cost=0.00..1.12 rows=5 width=696) (actual time=0.042..0.054 rows=5.00 loops=1)
Filter: ((department)::text = 'Engineering'::text)
Rows Removed by Filter: 5
Buffers: shared hit=1
Planning Time: 0.126 ms
Execution Time: 0.139 ms
Even though idx_employees_department exists on this exact column, PostgreSQL still chose a sequential scan over using it. This isn’t a bug, on a table this small (9 rows), reading the whole table directly is actually faster than the overhead of consulting an index and then looking up each matching row separately. The query planner makes this choice based on real cost estimates, table size, and data distribution, not simply “an index exists, so use it.” On a table with millions of rows, the same query would very likely use idx_employees_department instead, an Index Scan line would appear in the plan.
EXPLAIN vs EXPLAIN ANALYZE
EXPLAIN alone shows the planned approach without running anything, EXPLAIN ANALYZE actually executes the query and shows the real measured time and row counts alongside the plan (actual time=0.042..0.054, Execution Time: 0.139 ms). EXPLAIN ANALYZE is more informative but has a real side effect worth remembering: it genuinely runs the query, including any writes, running EXPLAIN ANALYZE on a DELETE or UPDATE actually deletes or updates the rows.
Reading the Plan
Key details worth watching for in any plan: Seq Scan (reads the whole table) versus Index Scan (uses an index to jump directly to matching rows), the rows= estimate versus the actual ... rows= count (a large mismatch between them can signal outdated table statistics), and Rows Removed by Filter (how many rows were read but didn’t match, a hint that an index on the filtered column might help at a larger scale).
Try It
- Run
EXPLAIN SELECT * FROM employees;(noWHEREclause) and read the plan, explain why it’s necessarily a sequential scan. - Run
EXPLAIN ANALYZEon a query filteringemployeesbysalary > 70000, and note the actual execution time. - Compare the
rows=estimate to theactual ... rows=count in your result from question 2, and note whether they match. - Explain, in your own words, why running
EXPLAIN ANALYZEon aDELETEstatement is riskier than running plainEXPLAINon it.
Recap
EXPLAINshows PostgreSQL’s planned execution strategy without running the query.EXPLAIN ANALYZEactually runs the query, showing real measured time and row counts alongside the plan, but with real side effects for write statements.- The query planner chooses between a sequential scan and using an available index based on cost estimates, not automatically, a small table often favors a sequential scan even with a relevant index present.
Next lesson: query optimization basics, reading an execution plan to spot a real problem.