Lesson 04: Concurrency

MVCC

How do databases handle millions of concurrent users? If Alice is running a slow report that reads the whole users table (which takes 5 minutes), and Bob tries to update his username, should Bob be blocked for 5 minutes?

In older databases, yes. Reading acquired a lock, and writers had to wait. But modern databases use Multi-Version Concurrency Control (MVCC) to solve this: Readers do not block writers, and writers do not block readers.

Data is Immutable

MVCC solves the locking problem with a simple trick: when you UPDATE a row, the database doesn't actually overwrite the data on disk. Instead, it creates a brand new, invisible copy of the row with a higher Version Number.

MVCC Simulator

Start a slow Read query that takes 10 seconds. While it's running, click the Write query to update Bob's balance. Notice how neither query blocks the other.

Read Txn: SELECT sum(balance) (started @ T=1)
Write Txn: UPDATE (started @ T=2)
ID
Balance
Version (T)
Alice
$100
T=1
Bob
$500
T=1
Database idle. Current time: T=1.

Garbage Collection

Because the Read transaction started at T=1, it completely ignored Bob's new T=2 row. It saw a perfectly consistent snapshot of the database at the exact millisecond it started.

Of course, if you never delete old versions, your hard drive will fill up. MVCC databases rely on a background process called Garbage Collection (or Vacuuming in PostgreSQL). Once the database guarantees that no active Read transactions are looking for T=1 data anymore, the garbage collector comes along and permanently deletes the old row.

Check yourself

1. What is the core mechanism MVCC uses to prevent writers from blocking readers?

By maintaining multiple versions of a row concurrently, MVCC ensures that a long-running Read transaction sees a consistent snapshot of the data from the moment it started, completely ignoring any new writes.