EXPLAIN and EXPLAIN ANALYZE reveal PostgreSQL’s execution plan, helping you pinpoint bottlenecks and tune queries.
An execution plan is PostgreSQL’s step-by-step roadmap for running a query.It shows chosen indexes, join strategies, and estimated costs, allowing you to diagnose slow SQL.
Prefix your statement with EXPLAIN
to see the planner’s estimates, or EXPLAIN ANALYZE
to run the query and append actual runtime metrics.
EXPLAIN ANALYZE SELECT o.id, o.total_amount
FROM Orders o
JOIN Customers c ON c.id = o.customer_id
WHERE c.email LIKE '%@gmail.com' AND o.order_date > NOW() - INTERVAL '30 days';
The output lists nodes such as Seq Scan, Index Scan, or Hash Join, each with cost, rows, and timing.
Focus on nodes with the highest actual time or rows mismatch.Sequential scans on large tables, nested-loop joins on big result sets, and sorts spilling to disk are prime suspects.
Add or tune indexes, rewrite filters to be sargable, force parallelism via set max_parallel_workers_per_gather
, or refactor joins/subqueries. Rerun EXPLAIN ANALYZE
to verify improvement.
BUFFERS
shows cache hits vs. reads; VERBOSE
reveals column-level details; FORMAT JSON
feeds visual tools. Combine them for deeper insight.
1) Always compare estimated vs.actual rows.
2) Test on production-like data.
3) Keep statistics current with ANALYZE
.
4) Save baseline plans to track regressions.
Skipping ANALYZE
leads to stale stats and bad plans. Misreading cost units as milliseconds causes wrong conclusions; they are abstract weights, not time.
Use EXPLAIN
for planning insight, EXPLAIN ANALYZE
for real metrics, watch high-cost nodes, and iterate with indexing or query rewrites.
.
It executes the query, so avoid it on heavy write statements or long-running reports. Use a replica or limit results.
Wrap EXPLAIN in INSERT INTO plan_log(plan) VALUES (EXPLAIN (FORMAT JSON) ...)
or save pg_stat_statements
output with auto_explain
.
Run ANALYZE
to refresh stats, increase default_statistics_target
, or create extended statistics on correlated columns.