Module 1: Reading the Plan
How to read an EXPLAIN plan — and why a Seq Scan is not a verdict.
How to read a plan
An EXPLAIN shows the planner's intended strategy as a tree of operators (scans, joins, sorts, aggregates). EXPLAIN ANALYZE actually runs the query and adds real numbers — so you can compare what the planner guessed with what happened.
Index Scan using orders_customer_id_idx on orders
(cost=0.43..8.45 rows=12 width=64)
(actual time=0.018..0.022 rows=11 loops=1)- operator —
Index Scan,Seq Scan,Nested Loop,Hash Join,Sort,Aggregate. - cost=start..total — the planner's estimate in arbitrary units. Useful for comparing plans, not a time.
- rows / width — estimated rows out, and average row size in bytes.
- actual time / rows / loops — from
ANALYZEonly: real time, real rows, and how many times this node ran.
EXPLAIN ANALYZE. A plain EXPLAIN shows estimates only.Read the tree bottom-up and inside-out: the deepest, most-indented nodes run first and feed their parents. loops=N on an inner node means it ran N times — multiply its per-loop cost by N to get the real work.
Ship, Flag, Escalate — and the Seq Scan myth
Same three calls as every Reviewer's Eye course, tuned for plans:
- Ship — the plan is appropriate for the data. An index scan, a tiny-table seq scan, a nested loop over a small outer.
- Flag — a definite performance bug: a selective query seq-scanning a huge table, a nested loop over two large unindexed inputs, deep
OFFSET. - Escalate — the verdict depends on facts you can't see here: the real table size, whether stats are current (
last_analyze), the live data distribution. Route it to someone who can runEXPLAIN ANALYZEon production.
Seq Scan when all three hold: the table is large, the predicate is selective (returns a small fraction), and no usable index exists. Miss any one and the seq scan is probably correct.Warm-up below: four plans, two of them safe — including a seq scan that's perfectly fine. See where your eye sits.
Drill — Reading the Plan
Judge each artifact. You are scored on calibration: catches vs false alarms.
SELECT name FROM countries WHERE iso_code = 'JP'; Seq Scan on countries (cost=0.00..4.30 rows=1 width=20) (actual time=0.012..0.020 rows=1 loops=1) Filter: (iso_code = 'JP'::text)Planning Time: 0.08 msExecution Time: 0.03 ms
Capstone: the Capstone: Calibration Exam (16 cards) from The Query Eye unlocks once modules are complete.