Как работает snapshot в базе данных?
Что проверяют
Понимаете ли вы, как база даёт транзакции согласованную картину данных без блокировок на чтение. Следом обычно спрашивают, какие аномалии snapshot isolation всё-таки допускает и чем Read Committed отличается от Repeatable Read.
Как отвечать
Обычно имеют в виду снимок в MVCC, реже снимок тома для бэкапа; отвечайте про первый.
Главное: снимок не копирует данные. Каждое изменение строки создаёт её новую версию, старая остаётся, а снимок это правило видимости: какие транзакции считались завершёнными в момент его создания. В PostgreSQL он описывается границами xmin, xmax и списком активных транзакций, у каждой версии строки свои xmin и xmax. В MySQL InnoDB и Oracle старые версии восстанавливаются из undo.
Момент создания снимка зависит от уровня изоляции:
- Read Committed: новый снимок на каждый оператор. Два одинаковых
SELECTв одной транзакции могут вернуть разное; - Repeatable Read: один снимок на всю транзакцию, от первого запроса. В PostgreSQL при конкурентном обновлении той же строки транзакция получает ошибку сериализации;
- Serializable: в PostgreSQL это SSI поверх снимков, дополнительно ловит write skew.
В Java уровень задают через Connection.setTransactionIsolation() или @Transactional(isolation = Isolation.REPEATABLE_READ) в Spring, и такой код обязан уметь повторять транзакцию. pg_dump сам работает внутри одного снимка, поэтому дамп согласован без остановки записи.
Цена подхода: версии копятся. Долгая транзакция держит старый снимок, VACUUM не может убрать мёртвые версии, таблицы разрастаются. В Oracle это проявляется ошибкой ORA-01555: snapshot too old.
Где спотыкаются
Говорят, что снимок это копия всех строк на момент начала транзакции. Правильная модель это версии строк плюс правило видимости.
Считают snapshot isolation полной сериализуемостью. Он допускает write skew: две транзакции читают одно и то же, каждая пишет в свою строку, и вместе они нарушают инвариант, например оба дежурных врача снимаются с дежурства.
Держат транзакцию открытой на время внешнего HTTP-вызова или долгой пакетной обработки. На нагруженной базе это раздувание таблиц.