Что такое MVCC и как он позволяет читать без блокировок?
- Как PostgreSQL хранит версии строк?
- Зачем нужен VACUUM?
- Почему читатели не блокируют писателей?
Многоверсионность: изменение строки создаёт новую версию, а старая остаётся. Каждая транзакция читает снимок — версии, подтверждённые до её начала (или до начала запроса).
- Читатели не блокируют писателей и наоборот; блокируются только два писателя одной строки
- В PostgreSQL версия помечена xmin/xmax — номерами создавшей и удалившей транзакций
- Старые версии убирает VACUUM; долгие транзакции мешают уборке — таблица «раздувается»
А ещё В Oracle и InnoDB старые версии лежат в undo-журнале, а не в таблице
Подробно
Без многоверсионности согласованное чтение требует блокировок: пока транзакция читает, писатель ждёт, и наоборот. MVCC снимает это противоречие — у каждой транзакции своя точка зрения на данные.
Как это устроено в PostgreSQL:
- каждая версия строки (tuple) хранит
xmin— транзакцию, которая её создала, иxmax— транзакцию, которая её удалила или заменила; UPDATEне перезаписывает строку: он ставитxmaxстарой версии и вставляет новую сxmin= текущая транзакция;- снимок — список транзакций, которые на момент его взятия уже завершились; версия видна, если её
xminподтверждён в снимке, аxmax— нет; - в Read Committed снимок берётся на каждый запрос, в Repeatable Read — один на всю транзакцию.
Что даёт: длинный отчёт видит согласованное состояние базы на момент начала и никого не блокирует. Писатели блокируют друг друга только на одной и той же строке — второй ждёт коммита или отката первого.
Цена — старые версии. Они нужны, пока жива транзакция, которая может их увидеть. Убирает их VACUUM (autovacuum в фоне): освобождает место под новые версии. Проблемы:
- раздувание (bloat) — частые UPDATE при отстающем автовакууме;
- долгая транзакция или забытая
idle in transactionдержит горизонт: ни одна версия новее её начала не может быть убрана во всей базе. Таблицы пухнут, запросы замедляются. Ищут черезpg_stat_activity, ставятidle_in_transaction_session_timeout; - переполнение счётчика транзакций — 32-битные номера, нужна заморозка (freeze) старых строк, иначе база остановится для защиты.
Другие реализации. InnoDB и Oracle меняют строку на месте, а прошлую версию кладут в undo-журнал; читатель со старым снимком восстанавливает нужную версию из undo. Уборка — purge-поток. Плюс: таблица не пухнет; минус: долгий снимок раздувает undo и замедляет чтения.
MVCC и аномалии. Снимок защищает от грязного и неповторяемого чтения, но не от всех аномалий: на Repeatable Read (Snapshot Isolation) возможна асимметрия записи (write skew). Полную сериализуемость PostgreSQL даёт уровнем Serializable (SSI) — с откатом транзакций при конфликте.
Пример
-- сеанс 1
BEGIN ISOLATION LEVEL REPEATABLE READ;
SELECT balance FROM accounts WHERE id = 1; -- 100
-- сеанс 2: UPDATE accounts SET balance = 50 WHERE id = 1; COMMIT;
SELECT balance FROM accounts WHERE id = 1; -- всё ещё 100 — свой снимок
COMMIT;
SELECT xmin, xmax, balance FROM accounts WHERE id = 1; -- видно номер транзакции-создателяЧто хотят услышать
- Версии строк вместо перезаписи, снимок у транзакции.
- Почему читатели и писатели не блокируют друг друга.
- Устройство в PostgreSQL: xmin/xmax, VACUUM.
- Проблема долгих транзакций и раздувания.
- Отличие от undo-подхода и связь с уровнями изоляции — плюс.
Частые ошибки
- Считать, что MVCC устраняет все конфликты записи.
- Не связывать «таблица распухла» с открытой долгой транзакцией.
Проверьте себя
Один верный вариант. Подумайте, потом откройте ответ.
Показать варианты и ответ
- ✓Изменение создаёт новую версию строки, транзакция читает снимок — читатели не блокируют писателей
- ✗MVCC блокирует строку на чтение до конца транзакции, а старые версии удаляются сразу, поэтому писатели всегда ждут читателей
- ✗Старые версии строк удаляются сразу при изменении
- ✗При MVCC два писателя могут менять одну строку одновременно без блокировки
Что спросят дальше
Связанные вопросы
Разбор собеседования с sotto
После собеседования sotto разбирает разговор: оценка, каждый вопрос — хорошо, частично или слабо, чего не хватило в ответе и над чем поработать к следующему разу. Первые 30 минут бесплатно.