linuxlab.io
Учебники▾
  • Линукс и сети
    Файловая система, процессы, TCP/IP, BGP и OSPF
    →
  • Terraform и IaC
    HCL, state, plan/apply на sandbox LocalStack
    →
  • Git и GitHub
    Объектная модель, plumbing, ветвление, GitHub Actions
    →
Все учебники →
ЦеныО платформеВойтиСоздать аккаунт
/
Intro
Lessons
Footer
linuxlab-УчебникиЦеныО платформеКонфиденциальность и куки
Copyright © 2026 LinuxLab. Все права защищены.
linuxlab.io
Учебники▾
  • Линукс и сети
    Файловая система, процессы, TCP/IP, BGP и OSPF
    →
  • Terraform и IaC
    HCL, state, plan/apply на sandbox LocalStack
    →
  • Git и GitHub
    Объектная модель, plumbing, ветвление, GitHub Actions
    →
Все учебники →
ЦеныО платформеВойтиСоздать аккаунт
/
  • Введение
  • Главы
  • How it worksскоро
  • Уроки
  • База знаний
  • Собеседование
home/postgres/kb/MVCC и видимость/snapshot

kb/mvcc ── MVCC и видимость ── intermediate

Снимок данных (snapshot)

Снимок - это не копия данных, а три числа: xmin, xmax и список активных xid между ними. Плюс правило, как по ним решать видимость версии. По снимку транзакция отделяет «прошлое» (зафиксировано до неё) от «настоящего» (идёт прямо сейчас) и «будущего» (ещё не начато). Дёшево по памяти, дорого по числу соединений.

view as markdownaka: data-snapshot, mvcc-snapshot

Частое заблуждение: «снимок - это фотография таблицы на момент старта». На деле снимок не копирует ни байта данных. Это компактный набор чисел, по которому транзакция вычисляет, какие версии строк ей видны.

Посмотреть текущий снимок:

sql
SELECT pg_current_snapshot();
-- 787:787:

Формат - xmin:xmax:список. Здесь оба числа равны и список пуст, значит активных транзакций рядом нет. Под нагрузкой это выглядело бы как 100:105:101,103 - три числа и больше ничего.

Три границы времени

Часть снимкаСмысл
xminниже этого xid всё уже решено (зафиксировано или откатилось)
xmaxэтот xid и выше ещё не существовали на момент снимка
списокxid между xmin и xmax, что шли прямо в момент снимка

Снимок делит транзакции на три зоны. Всё ниже xmin - прошлое: результат известен. Всё в списке - настоящее: идёт сейчас, результат ещё не виден. Всё выше или равно xmax - будущее: на момент снимка не начиналось.

Правило видимости через снимок

Версия строки видна, если её xmin:

  • меньше xmin снимка - точно в прошлом, и если транзакция коммитнулась, версия видна; либо
  • между xmin и xmax, не в списке активных, и зафиксирован по clog.

И при этом xmax версии не должен быть «уже зафиксированным в прошлом» - иначе версия удалена с точки зрения снимка. Полные правила для пары полей - в xmin-xmax.

Когда снимок берётся

Момент взятия снимка зависит от уровня изоляции (см. isolation-levels). На Read Committed новый снимок берётся на каждый оператор: соседний SELECT в той же транзакции может увидеть свежие чужие коммиты. На Repeatable Read и Serializable снимок берётся один раз на транзакцию и держится до конца - поэтому повторное чтение даёт тот же результат.

Снимок можно даже передать в другую сессию, чтобы две транзакции видели ровно одно и то же. Это snapshot-export.

Подводный камень: цена снимка растёт с числом соединений

Снимок дёшев по памяти, но не бесплатен по построению. Чтобы узнать список активных транзакций, сервер обходит структуру со всеми работающими бэкендами. Чем больше открытых соединений, тем дороже взять снимок - а берётся он часто. Поэтому тысячи почти простаивающих соединений вредят, даже когда «ничего не делают»: каждый из них утяжеляет снимок всем остальным. Отсюда правило держать пул соединений умеренным. А долгая транзакция, которая держит снимок открытым, заодно отодвигает горизонт уборки мусора (см. transaction-horizon).

§ команды

bash
SELECT pg_current_snapshot();

Текущий снимок в формате xmin:xmax:список активных xid

bash
SELECT pg_snapshot_xmin(pg_current_snapshot()), pg_snapshot_xmax(pg_current_snapshot());

Разобрать снимок на границы прошлого и будущего

bash
SELECT pg_current_xact_id_if_assigned();

Реальный xid текущей транзакции (пусто, если она ещё ничего не писала)

§ см. также

  • xmin-xmaxxmin, xmax и правила видимостиУ каждой версии строки два транзакционных штампа: xmin (кто вставил) и xmax (кто пометил устаревшей, 0 - если жива). Версия видна транзакции, если её xmin уже зафиксирован и попадает в снимок, а xmax либо пуст, либо ещё не зафиксирован, либо не виден снимку. По этим двум числам строится вся видимость.
  • isolation-levelsУровни изоляции в PostgreSQLPostgreSQL различает три уровня изоляции. Read Committed (по умолчанию) берёт свежий снимок на каждый оператор. Repeatable Read берёт один снимок на транзакцию и держит его до конца. Serializable добавляет проверку, что транзакции можно выстроить в строгий порядок. Грязного чтения в PostgreSQL не бывает ни на одном уровне.
  • snapshot-exportЭкспорт снимка между сессиямиpg_export_snapshot() возвращает идентификатор снимка, а другая сессия через SET TRANSACTION SNAPSHOT берёт ровно тот же снимок и видит данные в том же срезе времени. Так работает параллельный pg_dump: все рабочие процессы выгружают согласованную копию. Экспортирующая транзакция должна оставаться открытой.
  • clog-hint-bitsclog и подсказки фиксации (hint bits)Зафиксирована транзакция или откатилась, хранит clog (каталог pg_xact) - всего два бита на транзакцию. Чтобы не дёргать clog при каждом чтении строки, результат проверки кэшируется в самой строке подсказками фиксации в t_infomask. Первый прочитавший строку ставит подсказку - и тем самым пачкает страницу, даже если это был обычный SELECT.
  • transaction-horizonГоризонт транзакцииГоризонт - минимум backend_xmin по всем активным транзакциям. Версию строки можно убрать, только если она стала мёртвой раньше горизонта. Одна долгая или idle-in-transaction транзакция отодвигает горизонт назад и запрещает уборку мусора во всей базе.
Footer
linuxlab-
Copyright © 2026 LinuxLab. Все права защищены.
Учебники
Цены
О платформе
Конфиденциальность и куки