/explain/xmin

xmin

Every row version in a heap carries two hidden system columns: xmin, the transaction id that created it, and xmax, the transaction id that deleted or superseded it. Postgres never overwrites a row in place: an UPDATE writes a new version and stamps the old one’s xmax. A transaction sees a version only if its xmin is committed and visible to that transaction’s snapshot, and its xmax is not. Old versions stay on disk until vacuum proves no live snapshot can still need them; that backlog is what n_dead_tup counts.

DEMO — toy table, 4 rowsnext xid 4711
ctidxminxmaxpayloadvisibility
(0,1)4702—'checkout'visible
(0,2)4703—'signup'visible
(0,3)4707—'refund'visible
(0,4)4710—'login'visible
LIVE / DEAD TUPLES
4 / 0
HEAP VERSIONS ON DISK
4
OPEN SNAPSHOT
none

UPDATE writes a new version and stamps the old row’s xmax. Open a snapshot first to see vacuum blocked.

SEE ALSO
xmaxdead tuplexmin horizon← back to start
The demo shows one heap page and ignores HOT chains, index entries, and the visibility map. Real xids are 32-bit and compared modulo 2^31; see PostgreSQL docs §66.4 “Visibility Map” and §25.1.5 “Preventing Transaction ID Wraparound Failures”.
xmin — robovac