Overview

Multiversion concurrency control gives each statement a snapshot of the data instead of making readers wait for writers. In PostgreSQL’s words, “reading never blocks writing and writing never blocks reading”. The price is that an UPDATE or DELETE leaves the old row version behind, so vacuum must reclaim it and long-running transactions cause bloat.

Rules

  • Snapshot scope follows transaction-isolation: Read Committed takes a new snapshot per statement; Repeatable Read and Serializable keep one for the whole transaction.
  • Writers still block writers on the same row. Use row locks or optimistic-locking for read-modify-write conflicts.
  • Every update writes a new row version, and new index entries unless it is a HOT update (write-amplification).
  • Old versions live until no snapshot can see them, so an idle-in-transaction session blocks cleanup. Keep transactions short.
  • Implementations differ: PostgreSQL keeps old versions in the table, while MySQL InnoDB keeps them in undo logs.
SELECT xmin, xmax, * FROM accounts WHERE id = 1;  -- row-version metadata