Pebellslearn by building
0%
RoadmapsMatrixCoursesSandboxSign in
High Level Database Concepts  ›  Lesson

MVCC

MVCC 15 minMVCC writes a new row version on every change and lets each snapshot see the versions alive when it began, so readers and writers do not block each other.

MVCC

At 9 a.m. an analyst starts a slow report over all of Pedal's rentals, while riders keep ending rides. In many older databases one side would have to wait for the other. In PostgreSQL neither waits, and the report still sees a consistent picture. The mechanism is called multi-version concurrency control.

The rule

Never overwrite a row: write a new version, and let each snapshot choose.

When you UPDATE a row, PostgreSQL does not change it in place. It writes a new version of the row and marks the old one as ended. Every version carries two hidden fields:

  • xmin: the id of the transaction that created this version.
  • xmax: the id of the transaction that deleted or replaced it (empty while it is current).

Each statement (or, in REPEATABLE READ and SERIALIZABLE, the whole transaction) works from a snapshot: a note of which transactions had committed when it started. A version is visible if its creator had committed by then and its remover had not.

SELECT xmin, xmax, bike_id, available FROM bikes WHERE bike_id = 7;

What follows from this:

  • Readers never block writers, and writers never block readers. The report reads old versions while updates add new ones.
  • Two writers on the same row still queue: the second waits for the first to commit or roll back.
  • DELETE only sets xmax; the row stays on disk.
  • Old versions that no snapshot can see any more are dead tuples. They waste space until VACUUM marks it reusable. The autovacuum background workers do this for you, and also refresh planner statistics.
  • Transaction ids are 32-bit and wrap around, so VACUUM also freezes old rows. If autovacuum is blocked for too long, PostgreSQL will eventually refuse new writes to protect data.

The shortcut

Picture every row as a stack of versions, each labelled "born in transaction X, died in transaction Y". To predict what a session sees, ask: which version was alive when my snapshot was taken?

The report and bike 7Step 1 of 4
  1. Snapshot taken

    The report starts at 9:00. Bike 7's only version says available = false, created by transaction 500.

The trap is an idle transaction left open for hours, for example a forgotten psql session after BEGIN. Its snapshot keeps every newer dead tuple "maybe needed", so autovacuum cannot remove them and tables bloat.

Drills

Answer fast — trust the rule.

quick drill

What does an UPDATE do to the physical row in PostgreSQL?

quick drill

A long SELECT is running on rentals. Does an UPDATE on rentals from another session have to wait for it?

quick drill

What removes dead tuples so their space can be reused?

quick drill

A session ran BEGIN six hours ago and went idle. Why does the DBA care?

Remember

  • Never overwrite a row: write a new version, and let each snapshot choose.
  • Ask which version was alive when the snapshot was taken.
  • Dead tuples need VACUUM; idle open transactions stop it working.

Practice — level up

0/1 solved

Write your answer, then compare it with a rubric and a model answer.

ExplainWhy is the table bloating?

The rentals table has grown to three times its real size, and pg_stat_activity shows a session 'idle in transaction' since yesterday. Explain the link using MVCC and what the DBA should do.