Query Profiling and EXPLAIN
Learning Focus
Use this lesson to diagnose slow queries with EXPLAIN (ANALYZE, BUFFERS) and find real offenders with pg_stat_statements.
Concept Overview
Query tuning is evidence-driven:
- identify the slow query
- inspect the plan
- fix the root cause (indexes, query shape, stats)
- measure again
The Profiling Toolkit
| Tool | What it shows |
|---|---|
EXPLAIN | estimated plan |
EXPLAIN (ANALYZE) | actual execution time and row counts |
EXPLAIN (ANALYZE, BUFFERS) | buffer hits/reads (I/O behavior) |
pg_stat_statements | top queries by time/calls |
EXPLAIN Basics
EXPLAIN (ANALYZE, BUFFERS)
SELECT order_id, amount
FROM orders
WHERE customer_id = 42
ORDER BY created_at DESC
LIMIT 50;
Look for:
Seq ScanvsIndex Scan- estimated vs actual rows
- sorts that spill to disk
pg_stat_statements
Enable (if available):
CREATE EXTENSION IF NOT EXISTS pg_stat_statements;
Top queries by total time:
SELECT query, calls, total_exec_time, mean_exec_time
FROM pg_stat_statements
ORDER BY total_exec_time DESC
LIMIT 10;
Common Mistakes & Troubleshooting
| Mistake | What happens | Fix |
|---|---|---|
| Adding indexes without checking plans | Extra write cost, no benefit | EXPLAIN before/after |
| Ignoring stats | Planner chooses bad plans | Run ANALYZE, keep autovacuum healthy |
| Sorting huge result sets | Slow queries | Index ORDER BY columns or reduce rows earlier |
Best Practices
- Use
EXPLAIN (ANALYZE, BUFFERS)for real evidence. - Optimize the queries that matter (use stats/logs).
- Prefer small schema/query changes over blind tuning.
Quick Reference
EXPLAIN SELECT ...;
EXPLAIN (ANALYZE, BUFFERS) SELECT ...;
CREATE EXTENSION pg_stat_statements;
SELECT * FROM pg_stat_statements;