Снимок (см. snapshot) - это компактный набор чисел. Раз так, его можно не только взять, но и передать другой сессии, чтобы две транзакции видели базу в одинаковом срезе времени.
Как передать снимок
В первой сессии экспортируем снимок изнутри открытой транзакции:
BEGIN;
SELECT pg_export_snapshot();
-- 00000006-00000002-1
-- транзакцию НЕ коммитим: пока она открыта, снимок «живёт»
Во второй сессии берём этот же снимок первым же действием транзакции:
BEGIN;
SET TRANSACTION ISOLATION LEVEL REPEATABLE READ;
SET TRANSACTION SNAPSHOT '00000006-00000002-1';
-- теперь эта транзакция видит данные точно так же, как первая
С этого момента обе сессии видят один и тот же набор версий: чужие коммиты, случившиеся после экспорта, скрыты от обеих.
Жёсткие условия
Механизм требовательный, и не зря:
- принимающая транзакция должна быть на уровне Repeatable Read или Serializable (см. isolation-levels) - на Read Committed снимок берётся на каждый оператор, делить нечего;
SET TRANSACTION SNAPSHOTдолжен идти до любого запроса в транзакции, пока у неё ещё нет собственного снимка;- экспортирующая транзакция обязана оставаться открытой, пока все принимающие не подхватили снимок. Закроется раньше - идентификатор станет недействительным.
Зачем это нужно: параллельный бэкап
Главный потребитель - pg_dump -j (параллельная выгрузка). Чтобы дамп был
согласованным, все рабочие процессы должны видеть базу в один и тот же
момент. Ведущий процесс экспортирует снимок, остальные подхватывают его
через SET TRANSACTION SNAPSHOT - и выгружают разные таблицы, но из одного
среза времени. Без этого параллельный дамп мог бы поймать половину таблиц
до чужого коммита, половину после, и получить несогласованную копию.
Экспорт снимка - это не способ «поделиться данными» между сессиями, а способ договориться о точке во времени, из которой обе на эти данные смотрят.