# MVCC (Why Deleting is Too Hard) Let's say you ask the Lazy Elephant to log a change: "Hey, can you update Sarah's phone number to 555-0100?" If you were a naive, hard-working database, you would: 1. Walk over to the disk. 2. Find the exact [[Page]] where Sarah's `Tuple` lives. 3. Bring out a giant bucket of digital white-out. 4. Carefully erase the old number. 5. Inscribe the new number. Postgres absolutely **refuses** to do this. Why? Because writing `In-Place` is physically exhausting. The disk drive has to spin around right to the middle of a block, wait for exactly the right moment, and precisely edit a few bytes of binary data. Additionally, what if someone else is currently reading Sarah’s old phone number while you are erasing it? You'd have to physically block them at the door, put up a big "OUT OF ORDER" sign, make them wait, do your edit, and then let them back in. That requires confrontation. Confrontation is tiring. ## The Art of the Sharpie Instead of erasing anything, Postgres leverages **Multi-Version Concurrency Control (MVCC)**. When you tell the elephant to UPDATE a row, what it actually does is: 1. It ignores the old row entirely. 2. It walks to the nearest empty space at the end of the data file. 3. It completely writes a **brand new row** with Sarah's new phone number. 4. Then, it quickly walks past the old row, pulls out a tiny, invisible red Sharpie, and scribbles `EXPIRED ALREADY` with a timestamp across it. That's it. This is why it's called "Multi-Version". Every time you update a row, Postgres doesn't update anything. It just makes a completely new *version* of the row, and pretends the old one doesn't exist anymore for any transactions starting *after* you made the change. ### The Problem of Piled Up Garbage This sounds genius because nobody has to fight over reading and writing the same exact block of disk at the same time. But there is a catch. If you update a million rows... you haven't edited a million rows. You've just created a million brand-new rows, and left a million dead, crossed-out rows lying rotting on the floor. In Postgres terminology, these dead rows are called **"Bloat"**. If left unchecked, your `Page` files would just be massive landfills of crossed-out Sharpie notes, and Postgres would have to wade knee-deep through the garbage just to find the one valid, living row among the filth. This is exhausting. ### The Autovacuum Roomba So how does the Lazy Elephant keep his house clean without lifting a finger? He buys a Roomba. Postgres has a background maintenance worker called the **Autovacuum Daemon**. While the main database is busy doing nothing or answering your queries, the Roomba wakes up, slowly crawls around the disk, and silently sweeps up all the dead tuples that nobody could possibly ever view again because they are so old. When it sweeps them up, it doesn't even shrink the file size. That would require reorganizing the entire disk! Instead, it just marks that space as "Available for Rent", so the next time someone inserts a row, they can just toss it into that freshly vacuumed pothole instead of appending it to the end of the file. Doing the right thing means crossing it out, doing the least work possible means letting the background worker sweep it up later.