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 и видимость/serializable-ssi

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

Serializable и SSI

Serializable в PostgreSQL построен на снимке Repeatable Read плюс отслеживание опасных зависимостей чтения-записи между транзакциями (SSI). Транзакции не блокируются: сервер запоминает, что они читали, через предикатные блокировки SIRead, и если складывается опасный цикл, откатывает одну с ошибкой 40001.

view as markdownaka: ssi

Repeatable Read замораживает снимок и убирает неповторяющиеся и фантомные чтения. Но он пропускает аномалию посложнее: две транзакции, каждая из которых читает данные, изменяемые другой. Классический пример - перекос записи (write skew): оба врача снимают себя с дежурства, каждый видит, что второй ещё на смене, и в итоге дежурных не остаётся.

Serializable закрывает и это. В PostgreSQL он реализован как SSI - Serializable Snapshot Isolation.

Не блокировать, а наблюдать

SSI не заставляет транзакции ждать. Они идут на обычном снимке Repeatable Read (см. isolation-levels), а сервер параллельно следит за зависимостями между ними. Чтобы знать, кто что прочитал, он ставит предикатные блокировки - SIRead. Это не настоящие блокировки: они никого не останавливают, а лишь помечают «эта транзакция прочитала вот эти строки».

sql
-- под нагрузкой Serializable предикатные блокировки видны как SIReadLock
SELECT locktype, mode FROM pg_locks WHERE mode = 'SIReadLock';

Опасная структура и откат

SSI ищет в графе зависимостей опасный узор: транзакцию, которая и читает данные, изменённые другой, и сама изменяет данные, читаемые третьей. Когда такой цикл грозит нарушить сериализуемость, сервер жертвует одной из транзакций и откатывает её:

ERROR:  could not serialize access due to read/write dependencies among transactions

Код тот же 40001, что и у конфликта записи на Repeatable Read, но причина другая: не «кто-то опередил с записью», а «совместный порядок чтений и записей нельзя свести к последовательному». Реакция приложения та же - повторить транзакцию.

Цена и компромиссы

  • Гранулярность. Предикатные блокировки бывают на уровне строки, страницы или таблицы. Под нехваткой памяти они укрупняются, и тогда появляются ложные срабатывания - лишние откаты там, где реального конфликта не было.
  • Короткие транзакции. Чем дольше живёт транзакция, тем больше она накопит зависимостей и тем выше шанс попасть под откат.
  • Готовность повторять. Serializable снимает с разработчика ручные блокировки SELECT FOR UPDATE, но взамен требует цикла повтора по 40001.

SSI - это сделка: пишешь код так, будто транзакции выполняются строго по очереди, а движок сам ловит случаи, где параллельность это нарушила бы, и заставляет повторить.

§ команды

bash
BEGIN ISOLATION LEVEL SERIALIZABLE;

Открыть транзакцию с гарантией сериализуемости через SSI

bash
SELECT locktype, mode FROM pg_locks WHERE mode = 'SIReadLock';

Предикатные блокировки, которыми SSI отмечает прочитанное

bash
SHOW max_pred_locks_per_transaction;

Лимит предикатных блокировок до укрупнения гранулярности

§ см. также

  • isolation-levelsУровни изоляции в PostgreSQLPostgreSQL различает три уровня изоляции. Read Committed (по умолчанию) берёт свежий снимок на каждый оператор. Repeatable Read берёт один снимок на транзакцию и держит его до конца. Serializable добавляет проверку, что транзакции можно выстроить в строгий порядок. Грязного чтения в PostgreSQL не бывает ни на одном уровне.
  • snapshotСнимок данных (snapshot)Снимок - это не копия данных, а три числа: xmin, xmax и список активных xid между ними. Плюс правило, как по ним решать видимость версии. По снимку транзакция отделяет «прошлое» (зафиксировано до неё) от «настоящего» (идёт прямо сейчас) и «будущего» (ещё не начато). Дёшево по памяти, дорого по числу соединений.
  • xmin-xmaxxmin, xmax и правила видимостиУ каждой версии строки два транзакционных штампа: xmin (кто вставил) и xmax (кто пометил устаревшей, 0 - если жива). Версия видна транзакции, если её xmin уже зафиксирован и попадает в снимок, а xmax либо пуст, либо ещё не зафиксирован, либо не виден снимку. По этим двум числам строится вся видимость.
Footer
linuxlab-
Copyright © 2026 LinuxLab. Все права защищены.
Учебники
Цены
О платформе
Конфиденциальность и куки