30-Second Glance
- SSI = snapshot isolation + abort on "dangerous structures": optimistic serializability where readers never block.
- Tracks read-write antidependencies (T1 reads what concurrent T2 wrote); a 2-cycle of them means a serial order is impossible → abort one side.
- PostgreSQL's
SERIALIZABLEis SSI: same snapshot semantics as repeatable read, plus predicate-aware SSI checks (SIREAD locks, no blocking). - Best for low-contention workloads with strict invariants; under hot-row storms abort rates spike — then prefer 2PL or explicit locks.
From Snapshot to Serializable
Snapshot Isolation fails exactly on predicate anomalies (Write Skew and Phantom Writes): disjoint writes, invisible phantoms. SSI (Cahill–Röhm–Fekete, Postgres 9.1+) closes the gap without taking blocking locks. Each transaction runs on its snapshot as usual, while the engine records:
- rw-antidependency
T1 --rw--> T2: T1 read a version that T2 (concurrent, overlapping lifetime) later overwrote — T1 appears "before" T2 but read stale data relative to T2's write. - Dangerous structure:
T1 --rw--> T2 --rw--> T3with a commit-order violation — in the simplified interview form, a cycle of rw-antidependencies among concurrent transactions. No serial order can satisfy all of them, so one transaction must abort (Postgres40001).
Crucially these are SIREAD (predicate) locks: they record what was read (including gaps/ranges, hence phantom detection) but never block anyone. They only cause aborts at commit time. Readers keep full MVCC non-blocking behavior — the headline advantage over Two-Phase Locking.
The On-Call Case Under SSI
Revisit the rota: T1 reads {Alice, Bob}, writes Alice; T2 reads {Alice, Bob}, writes Bob — concurrently. T1's read of Bob's row is antidependent on T2's write of Bob; T2's read of Alice's row is antidependent on T1's write of Alice. Cycle → whoever tries to commit second aborts with could not serialize access due to read/write dependencies. The survivor's decision was made on a snapshot the other concurrently invalidated — exactly right to retry.
False positives exist: the detector is conservative (it aborts some executions that were actually serializable) to keep tracking cheap. Measured SSI abort overhead on uncontended TPC-C is ~1–5%; pathological hot-spot workloads can see 10–30%+ abort rates, at which point pessimistic locking or partitioning wins.
Concrete Numbers
| Quantity | Typical value | Why it matters |
|---|---|---|
| SSI tracking cost | In-memory rw-graph + SIREAD entries until overlapping txns all commit | Short txns keep it trivial; long readers pin SSI state like snapshots pin VACUUM |
| Abort rate, low contention | <1–5% | Retry-with-backoff is invisible |
| Abort rate, hot spot | 10–50%+ | Signal to switch strategy (lock the hot row, partition, batch) |
| Safe-retry snapshot | Postgres DEFERRABLE serializable takes a safe snapshot (may wait) |
Read-only analytics get zero-abort serializable snapshots at the cost of initial wait |
| Where available | PostgreSQL SERIALIZABLE, FoundationDB, CockroachDB (variant) |
InnoDB SERIALIZABLE is 2PL-style locking instead — engine matters |
SSI vs 2PL: Choosing
| Dimension | SSI (optimistic) | 2PL (pessimistic) |
|---|---|---|
| Reader cost | Zero blocking, snapshot reads | S locks block writers; p99 suffers under contention |
| Failure mode | Aborts (40001) concentrated at commit |
Waits/deadlocks spread through execution |
| Hot spots | Abort storms | Lock queues + collapse |
| Predicate handling | SIREAD tracking, automatic | Gap/next-key locks, index-dependent |
| Best workload | Read-heavy + occasional strict writes; PG shops | Write-contended invariants; legacy RDBMS; when retries are unacceptable |
Interview line: "SSI when aborts are cheaper than waits (low contention, read-heavy); 2PL when waits are cheaper than aborts (known hot rows, short strict txns)."
Trade-offs
| Approach | Pros | Cons | Use when |
|---|---|---|---|
| SSI serializable | True serializability; non-blocking reads; automatic predicate coverage | Abort/retry logic mandatory; false positives; SSI state with long txns | Postgres OLTP with roster/booking/money invariants at normal contention |
| 2PL serializable | No abort storms; deterministic blocking | Deadlocks; p99 latency; gap-lock complexity | Hot-row strict workloads, InnoDB shops |
| Snapshot + constraints | Cheapest when invariants are constraint-shaped | Leaves general predicates exposed | Uniqueness/range invariants only |
| Serial execution | No anomalies, no aborts | Partition/sproc discipline | Partitionable high-TPS OLTP |
Interview One-Liners
- Q: SSI in one sentence? A: Optimistic serializability: run on snapshots, track read-write antidependencies including predicates, abort on cycles — readers never block.
- Q: What is an rw-antidependency? A: T1 read data that concurrent T2 overwrote — T1's decision rested on state T2 invalidated, so ordering T1 before T2 is suspect.
- Q: What triggers the abort? A: A dangerous structure (cycle of rw-antidependencies among overlapping txns) proving no equivalent serial order exists.
- Q: What are SIREAD locks — do they block? A: Non-blocking markers recording what (including gaps) a txn read; they exist only to detect phantoms and predicate cycles at commit.
- Q: Postgres
REPEATABLE READvsSERIALIZABLE? A: Same snapshot mechanics; SERIALIZABLE adds SSI tracking + dangerous-structure aborts. Both need40001retry handling. - Q: When does SSI lose to 2PL? A: Hot-spot write storms where optimistic aborts (10–50%+) cost more than pessimistic waiting — lock the hot domain instead.