Stage 1 of 9 · Model
What is actually running out?
Postgres tags each transaction with a 32-bit ID. Vacuum must periodically "freeze" old rows so IDs can be reused; if it falls too far behind, Postgres stops accepting writes rather than risk corrupting data.
What you need to know first
Postgres gives each transaction a 32-bit transaction ID. That's about 4 billion IDs, reused in a cycle. To make reuse safe, vacuum must "freeze" old rows so they no longer depend on their original transaction ID.
If vacuum falls too far behind, Postgres stops accepting writes rather than risk misreading old rows as new. That's wraparound, and it's a hard deadline.
Three different fixes target three different limits:
| Fix | What it divides |
|---|---|
| Read replicas | read load (every replica still replays every write) |
| Partitioning tables on one host | maintenance work per table (same host limits) |
| Sharding across hosts | write volume, table size and vacuum work |
See Partitioning and Replication.
Vacuum can't keep up with the primary's write volume. Do read replicas help?
No: replicas take reads, but the primary still does every write and all the vacuum work.
The limit is per-host writes and table size on the primary. Replicas don't touch it, and each replica replays the same writes.
What the stage asks
Which statements hold?
- Fails
Moving to a bigger instance would fix this for good.
They are already on the largest instance. And vacuum's work grows with table size, so a faster machine postpones the deadline without changing its direction.
- Fails
Adding read replicas would relieve the pressure.
Replicas take reads off the primary, but this is a write-volume and table-size problem on the primary. Every replica also replays every write.
- Holds
Splitting the largest tables into partitions on the same host makes each vacuum smaller, but every partition still shares one host's CPU, disk and connections.
Native partitioning helps maintenance, not capacity. The host's limits are the ceiling.
- Holds
Spreading workspaces across many hosts divides write volume, table sizes and vacuum work between them.
Each host holds a fraction of the data and receives a fraction of the writes, so every per-host limit is pushed back by roughly the number of hosts.
The reasoning
- Name the limit first: here, per-host write volume and table size.
- Replicas divide reads; partitioning on one host shrinks maintenance; only sharding divides writes.
- Transaction ID wraparound makes vacuum lag a hard deadline.
Name the limit before choosing the fix. Here it is per-host write volume and table size: replicas do not touch it, a bigger machine is not available, and partitioning inside one host only makes maintenance smaller. Horizontal Partitioning is the only option that divides the load itself. That justifies the cost, which is considerable: Notion described sharding as something they would rather have done earlier, while the data was smaller and the migration simpler.