Optimizing Query Performance

1. Using EXPLAIN

EXPLAIN SELECT * FROM orders WHERE customer_id = 42;

2. Using EXPLAIN ANALYZE

EXPLAIN (ANALYZE, BUFFERS) SELECT ... ;     -- actually runs query
Warning: ANALYZE executes the statement. Use BEGIN; ... ROLLBACK; for destructive queries.

3. Using EXPLAIN (BUFFERS)

EXPLAIN (ANALYZE, BUFFERS, WAL, SETTINGS) SELECT ... ;
OutputMeaning
shared hitPage in buffer cache
shared readPage read from disk
temp writtenSpill to disk (sort/hash)

4. Using EXPLAIN (VERBOSE)

EXPLAIN (VERBOSE) SELECT ... ;   -- shows output columns, schema-qualified names

5. Understanding Scan Types

ScanWhen Used
Seq ScanSmall / large-fraction read
Index ScanSelective predicate + ordering
Index Only ScanAll columns in index (visibility map OK)
Bitmap Heap ScanMany index entries → unique heap visits

6. Understanding Join Methods

MethodBest For
Nested LoopSmall outer + indexed inner
Hash JoinEquality, large inputs fit in work_mem
Merge JoinPre-sorted inputs

7. Understanding Node Types

-- Common: Aggregate, Sort, Limit, HashAggregate, Materialize,
-- Append, Gather, Gather Merge, Parallel Seq Scan, WindowAgg, Memoize (PG 14+)

8. Analyzing Costs

NumberMeaning
cost=startup..totalPlanner units
rowsEstimated rows
actual timeReal ms (with ANALYZE)
loopsTimes node ran

9. Identifying Bottlenecks

Note: Look for: large discrepancy between estimated and actual rows, Seq Scan on big tables with selective filter, Sort spilling to disk, Rows Removed by Filter very high.

10. Using Index-Only Scans

CREATE INDEX orders_cover ON orders(customer_id) INCLUDE (status);
VACUUM orders;       -- keep visibility map fresh
EXPLAIN SELECT customer_id, status FROM orders WHERE customer_id = 42;

11. Understanding Bitmap Heap Scans

-- Bitmap Index Scan builds bitmap of TIDs
-- Bitmap Heap Scan then fetches heap pages in physical order (less seek)

12. Using Parallel Query Execution

SET max_parallel_workers_per_gather = 4;
EXPLAIN SELECT count(*) FROM big_fact;     -- Gather → Parallel Seq Scan

13. Analyzing Join Order

SET join_collapse_limit = 8;          -- default; raise for many tables
SET from_collapse_limit = 8;

14. Identifying Missing Indexes

SELECT relname, seq_scan, seq_tup_read, idx_scan
  FROM pg_stat_user_tables
 WHERE seq_scan > 1000 AND seq_tup_read / seq_scan > 10000
 ORDER BY seq_tup_read DESC;

15. Using EXPLAIN (FORMAT JSON, FORMAT YAML)

EXPLAIN (ANALYZE, FORMAT JSON) SELECT ... ;     -- machine readable
EXPLAIN (FORMAT YAML)  SELECT ... ;