· 1 min read
Reading EXPLAIN ANALYZE like a profiler
Treat the plan as a flame graph. Find the node where estimated and actual rows diverge.
#postgres
EXPLAIN ANALYZE output looks like noise until you read it like a profiler: find where the time goes, then ask why the planner was surprised.
EXPLAIN (ANALYZE, BUFFERS)
SELECT * FROM orders WHERE customer_id = 42 AND status = 'open';
What I look at, in order
- Actual time of the slowest node, remembering it is per loop.
- Rows: estimated vs actual. A 100x gap means stale or missing statistics.
- Buffers.
shared readmeans disk;shared hitmeans cache. - Sort and hash nodes spilling to disk (
Sort Method: external merge).
Common fixes
- Run
ANALYZE, or raise the statistics target on skewed columns. - Add a composite index that matches the filter and sort order.
- Rewrite
ORacross columns into aUNION ALL.
Most slow queries are one wrong estimate away from a fast plan.