Ответ
Обновление строк в PostgreSQL происходит не путем изменения существующих данных на месте, а через механизм MVCC (Multi-Version Concurrency Control) — управление параллельным доступом посредством многоверсионности.
Когда вы выполняете команду UPDATE, происходит следующее:
- Создание новой версии: PostgreSQL создает новую версию строки (новую запись или
tuple) с обновленными данными. - Пометка старой версии: Старая версия строки не удаляется физически, а помечается как "неактуальная" для текущей и последующих транзакций. Это делается путем установки системного поля
xmaxв ID транзакции, которая произвела обновление. - Очистка: Со временем фоновый процесс
VACUUMнаходит и окончательно удаляет старые, уже невидимые ни для одной транзакции версии строк, освобождая место.
Пример:
-- Изначально есть строка с id = 1
UPDATE users SET name = 'Alice' WHERE id = 1;
После этой команды в таблице физически будут существовать две версии строки для id = 1, но только новая будет видна для последующих запросов.
Ключевые преимущества этого подхода:
- Отсутствие блокировок при чтении: Читающие транзакции не блокируют пишущие, и наоборот. Каждый видит свой "снимок" данных.
- Согласованность данных: Каждая транзакция работает с консистентным срезом данных, который не меняется во время ее выполнения.
- Возможность отката (Rollback): Для отката транзакции достаточно просто пометить созданные ею версии строк как недействительные.
Недостаток:
- Разрастание таблицы (bloat): Без регулярной работы
VACUUMтаблица будет занимать больше места на диске из-за "мертвых" версий строк.
Ответ 18+ 🔞
Да ты послушай, как эта штука работает, блядь! Это ж не просто так, "обновил и забыл". Нет, сука, там целый театр разворачивается, ёпта!
Вот смотри, в PostgreSQL, когда ты пишешь UPDATE, он не тыкается в старую запись, как мудак, и не меняет её на месте. Это было бы слишком просто, а значит — пиздец для параллельности. Вместо этого у них там целая система под названием MVCC (Multi-Version Concurrency Control), что в переводе на русский значит "управление параллельным доступом через многоверсионность". Звучит сложно, но щас разжуем.
Представь себе такую хуйню:
- Новая версия, как новая жизнь. Ты пишешь
UPDATE users SET name = 'Alice' WHERE id = 1;. И что делает база? Она не трогает старую запись, блядь! Она создаёт новую, свежую версию этой строки, уже с именем 'Alice'. Старая так и лежит, не тронутая. - Пометка старого хлама. Старую версию надо как-то списать. Её не удаляют, нет. Её просто помечают как "устаревшую, нахуй". Ставят на ней штамп, типа "эта версия актуальна только до транзакции номер такой-то". Теперь все новые запросы её игнорируют, видят только свежую.
- Уборщик-автомат. Если бы эти старые версии копились вечно, таблица бы раздулась, как жаба, и всё бы встало. Поэтому есть фоновый процесс
VACUUM. Это как дворник, который ходит и подметает эти уже никому не нужные, "мёртвые" версии строк, освобождая место. Без него — овердохуища мусора и тормоза.
Вот тебе пример кода, чтобы совсем понятно стало:
-- Допустим, была строка с id = 1 и name = 'Bob'
UPDATE users SET name = 'Alice' WHERE id = 1;
После этого запроса, физически на диске будут две записи для id = 1: старая 'Bob' и новая 'Alice'. Но все, кто придут после, увидят только 'Alice'. Старая — как призрак, невидимый, но занимающий место, пока VACUUM не придёт.
И зачем, спрашивается, этот цирк, блядь? А вот зачем, преимущества-то:
- Читатели не мешают писателям, писатели не мешают читателям. Одна транзакция может долго-долго что-то читать, а другая в это же время обновлять данные. И никто никого не заблокирует, пиздец как удобно! Каждая видит свой собственный, неизменный снимок данных.
- Консистентность — это святое. Твоя транзакция работает с данными, которые не прыгают у неё перед носом. Всё стабильно, как у дурака.
- Откат? Да хуй с ним, легко! Чтобы откатить транзакцию, не нужно откатывать каждое изменение. Достаточно просто сказать: "все версии, которые я создал, — недействительны, нахуй". И все новые запросы будут их игнорировать. Красота!
Но и без ложки дёгтя никуда, недостаток есть:
- Разбухание, блядь (bloat). Если
VACUUMпо каким-то причинам не справляется или его забыли настроить, таблица начинает жрать место в разы больше реально нужного. Потому что она хранит кучу старых, уже никому не нужных версий. Вот тогда и начинается: "чё-то у меня база распухла, ёпта!".
Вот такая, блядь, хитрая жопа, а не простое обновление. Всё для скорости и чтобы не блокировать друг друга.