# 6.1 The Relay Race (Wait Events)

In the Elephant Cafe, a query is not a single sprint; it is a **Relay Race**. To get a result back to a guest, the "Baton" of execution must pass through many different hands—from the CPU to the Disk, through the Network, and back again.
Most of the time, the database isn't actually "running." It is standing at a transition line, hand outstretched, waiting for the previous runner to arrive. In Postgres, these moments of standing still are known as **Wait Events**.
## Mechanics: The Snapshot of the Track
It is important to understand where these numbers come from. Postgres does not keep a high-resolution, historical "Log" of every micro-wait by default. Instead, performance views like `pg_stat_activity` rely on **Sampling**.
Monitoring a database is like taking a high-speed photo of a relay race track:
- **The Snapshot**: When you query `pg_stat_activity`, you are essentially looking at a single photo of the race. If you see an elephant standing perfectly still at the 100m mark, you know they are in a **Wait State**.
- **The Execution**: If you see an elephant blurred and running Mid-track, they have the baton and are currently utilizing the CPU (Execution).
- **The Blind Spot**: Because it is a snapshot, if a baton hand-off is incredibly fast, you might take a thousand photos and never actually "catch" the hand-off happening.
## The Three Families of Latency
When a runner is standing on the track without a baton, they are almost always waiting for one of three things:
1. **The Slow Runner (I/O Latencies)**: The previous runner is the Disk Storage. Because disks are physically slower than RAM, the next runner (the CPU) often spend 99% of the race just tapping their foot at the hand-off line.
2. **The Narrow Bridge (Lock Contention)**: The runner is stuck behind another team. Only one elephant can cross a narrow bridge at a time. The bottleneck isn't the runner's speed; it's the traffic jam caused by your application's **[[Chapter 4/4.4 - The Pinky Swear (Transactions)|Transaction Logic]]**.
3. **The Huddle (Synchronization/LWLocks)**: The process is waiting for a short-term coordination signal, like a group huddle to decide who gets to touch a shared memory buffer.
## The Cheat Sheet: Common Wait Events
When you sample `pg_stat_activity`, you will see a `wait_event_type` and `wait_event`. Here is the field guide to the runners currently standing still:
| `wait_event_type` | `wait_event` | Who are we waiting for? | Likely cause/fix |
| :--- | :--- | :--- | :--- |
| `IO` | `DataFileRead` | The Disk is bringing a page | Data not in `shared_buffers`; add memory or tune indexes |
| `IO` | `WALWrite` | The Scribe is writing to the diary | High write volume; move WAL to faster storage |
| `IO` | `BufFileRead` | The Temp File is being retrieved | `work_mem` too small for the sort/hash; increase `work_mem` |
| `Lock` | `relation` | Another team is using the whole table | DDL (`ALTER TABLE`) or manual `LOCK` blocking queries |
| `Lock` | `transactionid` | Another team is using this specific row | Another transaction is holding the row; commit old sessions |
| `LWLock` | `BufferContent` | Someone is already holding the plate | Hot-spot page contention; investigate indexes |
| `Client` | `ClientRead` | The Guest (the App) hasn't ordered yet | The app is slow or idle; check network or app logic |
> [!IMPORTANT]
> **Who has the baton?** If you see a `wait_event` of **NULL**, it means that specific process currently has the baton! It is actively running on the CPU and doing work.
By measuring the race, performance tuning stops being an exercise in guessing and becomes a strict exercise in identifying which runner is dropping the baton.
---
| ← Previous | ↑ Table of Contents | Next → |
| :--- | :---: | ---: |
| [[Chapter 6/6.0 - The Waiting Game (Workloads & Locking)\|Chapter 6 - The Waiting Game (Workloads & Locking)]] | [[Learn You a Postgres for Great Good\|Home]] | [[Chapter 6/6.1.1 - The Starvation (Client & Timeout)\|6.1.1 Client Stalls & Timeouts]] |