Что такое механизм MVCC в PostgreSQL и как он работает

Ответ

MVCC (Multi-Version Concurrency Control) — это основной механизм PostgreSQL для управления одновременным доступом к данным. Его ключевое преимущество — чтение данных никогда не блокирует запись, и наоборот.

Принцип работы

Вместо использования блокировок для каждой операции чтения, MVCC работает с версиями строк:

  1. Создание "снимка" данных: Каждая транзакция в момент своего старта получает "снимок" (snapshot) базы данных. Она видит только те данные, которые были зафиксированы (committed) до её начала.
  2. Версионирование строк:
    • При UPDATE строки старая версия не удаляется, а помечается как неактуальная. Рядом создается новая версия этой же строки.
    • При DELETE строка также не удаляется физически, а лишь помечается как удаленная для будущих транзакций.
  3. Изоляция транзакций: Активные транзакции продолжают работать со своими "снимками", игнорируя изменения, сделанные в других параллельных транзакциях, до тех пор, пока те не будут зафиксированы.
  4. Очистка: Фоновый процесс VACUUM периодически удаляет старые, уже невидимые ни для одной активной транзакции версии строк, освобождая место.

Пример

-- Исходное состояние: в таблице есть пользователь с именем 'Bob'
-- balance = 100

-- Транзакция 1 (началась в 10:00)
BEGIN;
SELECT balance FROM accounts WHERE user_id = 1; -- Видит balance = 100

-- Транзакция 2 (началась в 10:01, параллельно)
BEGIN;
UPDATE accounts SET balance = 150 WHERE user_id = 1;
COMMIT; -- Изменение зафиксировано

-- Транзакция 1 все еще работает со своим старым "снимком"
SELECT balance FROM accounts WHERE user_id = 1; -- По-прежнему видит balance = 100
COMMIT;

-- Новая транзакция, начатая после 10:01, увидит обновленное значение
SELECT balance FROM accounts WHERE user_id = 1; -- Увидит balance = 150

Этот подход обеспечивает высокую производительность в системах с большим количеством одновременных чтений и записей.

Ответ 18+ 🔞

А, MVCC, ёпта, это же та самая магия, которая в Постгресе позволяет не устраивать драку за данные! Чтоб никто никого не блокировал почём зря. Представь себе библиотеку, где каждый читатель приходит и получает свою личную, замороженную во времени копию книги, а писатели в это время спокойно в соседней комнате новое издание готовят. Никто никому не мешает — красота, блядь!

Как эта штука, блядь, работает

Вместо того чтобы вешать здоровенные замки на каждую строчку, Постгрес просто плодит версии данных, как сумасшедший. Вот смотри:

  1. "Снимок" на память: Каждая транзакция, только начавшись, делает моментальный снимок всей базы. И дальше она живёт в этой своей реальности, как в матрице, и видит только те данные, которые были закоммичены до её старта. Всё, что происходит параллельно — её не колышет, пока это не станет официальной историей.
  2. Версионирование — наше всё:
    • Делаешь UPDATE? Старая версия строки не стирается, она просто становится призраком для новых транзакций. Рядом лепится её свежая, обновлённая копия.
    • Удаляешь строку DELETE? Она физически никуда не девается! Просто на неё вешают табличку "удалена" для всех, кто придёт после.
  3. Изоляция, блядь, полная: Пока ты в транзакции, ты в своём мирке. Другие могут рядом творить что угодно — добавлять, менять, удалять. Ты этого не увидишь и не почувствуешь, пока не закончишь свою работу. Никаких грязных чтений, ёпта!
  4. Уборщик VACUUM: А иначе что? Эти версии строк будут копиться, как хлам в квартире распиздяя. Поэтому фоновый процесс VACUUM работает, как дворник — выгребает старые, уже никому не нужные версии, которые не видны ни одной живой транзакции. Освобождает место, чтоб не захламлялось.

Пример, чтобы совсем пиздец стало понятно

-- Допустим, у нас Вася, и у него на счету 100 рублей. Всё честно.

-- Транзакция 1 (зашла в систему в 10:00, как штык)
BEGIN;
SELECT balance FROM accounts WHERE user_id = 1; -- Видит свои честные 100 рублей. Спокойно.

-- Транзакция 2 (вломилась в 10:01, пока первая думает)
BEGIN;
UPDATE accounts SET balance = 150 WHERE user_id = 1; -- Банкомат сломался, начислил лишних 50!
COMMIT; -- Идиот, закоммитил это безобразие!

-- А наша первая транзакция всё ещё в своей старой реальности сидит, как будто ничего не было!
SELECT balance FROM accounts WHERE user_id = 1; -- Всё так же видит свои 100 рублей. Спокойствие, только спокойствие.
COMMIT;

-- А вот новая транзакция, которая стартанёт после всей этой ебалы, увидит уже новую, испорченную реальность.
SELECT balance FROM accounts WHERE user_id = 1; -- Опа, 150! Где справедливость?

Вот так вот, сука. Этот подход — просто овердохуища для систем, где нужно, чтобы куча народа одновременно и читала, и писала, не устраивая при этом давку и мордобой. Все довольны, все при своих снимках данных. Главное потом VACUUM не забывать запускать, а то место кончится, блядь.