Methodology for measuring query performance before and after optimization changes. Use with the Performance_lab/ exercises.
Optimization without measurement is guessing. A benchmark provides:
| Requirement | Detail |
|---|---|
| Data volume | Production-representative (not sample data) |
| Engine version | Same as production |
| Configuration | Same work_mem, buffer pool, etc. |
| Isolation | No concurrent queries during benchmark |
| Cache state | Test both cold and warm cache |
-- PostgreSQL: full diagnostic
EXPLAIN (ANALYZE, BUFFERS, TIMING, FORMAT TEXT)
SELECT ... ;
-- MySQL
EXPLAIN ANALYZE
SELECT ... ;
-- SQL Server
SET STATISTICS IO, TIME ON;
-- run query, inspect plan
| Metric | Source | Why |
|---|---|---|
| Total actual time | EXPLAIN ANALYZE | Primary success metric |
| Most expensive node time | Plan tree | Identifies bottleneck |
| Estimated vs. actual rows | Plan nodes | Statistics health |
| Buffer hits vs. reads | BUFFERS (PG) | Cache vs. disk I/O |
| Rows returned | Query result | Correctness check |
Report these values from your 5 runs:
| Statistic | Use |
|---|---|
| Median | Primary reported value (resistant to outliers) |
| Average | Secondary reference |
| P95 | Worst-case performance |
| Min | Best-case (warm cache, optimal plan) |
| Cache State | How to Achieve | When to Test |
|---|---|---|
| Cold | Restart engine or DISCARD ALL + read unrelated data |
First query after deployment |
| Warm | Run query once before measuring | Steady-state production |
A query that’s fast warm but slow cold is I/O-bound — the plan shape is fine, but data isn’t cached.
## Benchmark: [Query Name]
**Date**: YYYY-MM-DD
**Engine**: PostgreSQL 15.x
**Data volume**: employes = 5M rows
**Configuration**: work_mem = 64MB
| Version | Median (ms) | P95 (ms) | Plan Node | Rows |
|---|---|---|---|---|
| Baseline (v0) | | | Seq Scan | |
| After index (v1) | | | Index Scan | |
| After rewrite (v2) | | | Hash Join | |
**Change applied**: [describe single change]
**Improvement**: [percentage]
**Correctness verified**: [yes/no, row count match]
Hands-on benchmark exercises with baseline queries and progressive optimizations: