Databases Reference/Transactions & MVCC

MVCC Visibility & Implementation

Multi-version concurrency control — row versions, transaction IDs, snapshot visibility rules, UPDATE-as-DELETE+INSERT, bloat, and VACUUM/autovacuum as a storage maintenance problem.

4/5Overview: 30m

MVCC core idea

Multi-Version Concurrency Control — readers see a snapshot of the database as of transaction start; writers create new row versions without overwriting in place. No read locks on the hot path.

Postgres, InnoDB, and Oracle use variants; SQL Server uses mixed locking + row versioning.

Postgres tuple headers

Each heap row carries system columns:

ColumnRole
xminInserting transaction ID
xmaxDeleting/updating transaction ID (or 0)
ctidPhysical location (changes when row moves)

UPDATE = insert new version + mark old xmax; old row becomes dead tuple until vacuumed.

Snapshot visibility rules (simplified)

A row version is visible to transaction T if:

  1. xmin committed before T's snapshot, and
  2. xmax is null or aborted or committed after T's snapshot

pg_snapshot / txid_current() help debug visibility bugs in production.

HOT updates

Heap-Only Tuple optimization: if updated columns aren't indexed and new version fits same page, Postgres avoids updating every index — critical for update-heavy tables.

Bloat and VACUUM

Dead tuples occupy space and force scans to skip garbage. VACUUM reclaims space for reuse (doesn't always shrink file). VACUUM FULL rewrites table — locks exclusively.

SymptomLikely cause
Table 10× logical sizeLong-running tx blocking vacuum horizon
Index bloatHeavy updates on indexed columns
Transaction ID wraparoundAutovacuum falling behind — urgent

Monitor n_dead_tup, age(datfrozenxid), autovacuum lag.

InnoDB contrast (brief)

InnoDB stores undo logs in rollback segments; old versions reconstructed from undo chain. Purge thread reclaims undo. Same trade-off: MVCC convenience vs storage reclamation work.

vs locking-based serializable

MVCC snapshots can permit write skew under Repeatable Read. Serializable adds predicate locks or SSI tracking to detect dangerous interleavings.

Senior-level signal

"Postgres is slow after a migration" → check table bloat and autovacuum before adding indexes. Long idle in transaction sessions are a storage incident waiting to happen.

Where this goes next

RDBMS Replication & Failover — when one node's MVCC snapshot isn't enough because you have copies on other machines.

Further Reading

Hands-On Tasks (Optional)

Low-setup exercises — schema drills, paper walkthroughs, or optional local installs. No autograding; the goal is interview fluency on how data is stored.

  • Reason through a visibility scenario

    Txn A inserts row R. Txn B (started before A commits) SELECTs — does it see R? Txn C (started after A commits) UPDATEs R. What does A see if still open? Three sentences.

    15m