En el caso más simple, cuando insertamos una nueva fila en una tabla (y la transacción se confirma), será visible para todas las transacciones posteriores. Ver xmaxsiendo 0 en este ejemplo:
CREATE TABLE vis (
  id serial,
  is_active boolean
);
INSERT INTO vis (is_active) VALUES (FALSE);
SELECT ctid, xmin, xmax, * FROM vis;
  ctid │xmin │ xmax │ id │ is_active 
───────┼─────┼──────┼────┼───────────
 (0,1) │2699 │    0 │  1 │ f
Cuando lo actualizamos (porque el indicador se configuró FALSEpor accidente), cambia un poco:
UPDATE vis SET is_active = TRUE;
SELECT ctid, xmin, xmax, * FROM vis;
 ctid │ xmin │ xmax │ id │ is_active 
──────┼──────┼──────┼────┼───────────
(0,2) │ 2700 │    0 │  1 │ t
De acuerdo con el modelo MVCC que utiliza PostgreSQL, se escribió una nueva fila física y se anuló la anterior (esto se puede ver desde ctid). El nuevo todavía es visible para todas las transacciones posteriores.
Ahora sucede algo interesante cuando retrocedemos UPDATE:
BEGIN;
    UPDATE vis SET is_active = TRUE;
ROLLBACK;
SELECT ctid, xmin, xmax, * FROM vis;
 ctid  │ xmin │ xmax │ id │ is_active 
───────┼──────┼──────┼────┼───────────
 (0,2) │ 2700 │ 2702 │  1 │ t
La versión de fila permanece igual, pero ahora xmaxestá configurada en algo. A pesar de esto, las transacciones posteriores pueden ver esta fila (sin cambios).
Después de leer un poco sobre esto, puede descubrir algunas cosas sobre la visibilidad de la fila. Existe el mapa de visibilidad , pero solo indica si una página completa es visible; definitivamente no funciona en el nivel de fila (tupla). Luego está el registro de confirmación (aka clog), pero ¿cómo se da cuenta Postgres si tiene que visitarlo?
Decidí echar un vistazo a los bits de infomask para descubrir cómo funciona realmente la visibilidad. Para verlos, la forma más fácil es usar la extensión pageinspect . Para saber qué bits están configurados, creé una tabla para almacenarlos:
CREATE TABLE infomask (
  i_flag text,
  i_bits bit(16)
);
INSERT INTO infomask
VALUES 
('HEAP_HASNULL', x'0001'::bit(16)),
('HEAP_HASVARWIDTH', x'0002'::bit(16)),
('HEAP_HASEXTERNAL', x'0004'::bit(16)),
('HEAP_HASOID', x'0008'::bit(16)),
('HEAP_XMAX_KEYSHR_LOCK', x'0010'::bit(16)),
('HEAP_COMBOCID', x'0020'::bit(16)),
('HEAP_XMAX_EXCL_LOCK', x'0040'::bit(16)),
('HEAP_XMAX_LOCK_ONLY', x'0080'::bit(16)),
('HEAP_XMIN_COMMITTED', x'0100'::bit(16)),
('HEAP_XMIN_INVALID', x'0200'::bit(16)),
('HEAP_XMAX_COMMITTED', x'0400'::bit(16)),
('HEAP_XMAX_INVALID', x'0800'::bit(16)),
('HEAP_XMAX_IS_MULTI', x'1000'::bit(16)),
('HEAP_UPDATED', x'2000'::bit(16)),
('HEAP_MOVED_OFF', x'4000'::bit(16)),
('HEAP_MOVED_IN', x'8000'::bit(16)),
('HEAP_XACT_MASK', x'FFF0'::bit(16));
Luego verifiqué lo que hay dentro de mi vistabla: tenga en cuenta que pageinspectmuestra el contenido físico del montón, por lo que no solo se devuelven las filas visibles:
SELECT t_xmin, t_xmax, string_agg(i_flag, ', ') FILTER (WHERE (t_infomask::bit(16) & i_bits)::integer::boolean)
  FROM heap_page_items(get_raw_page('vis', 0)),
       infomask
 GROUP BY t_xmin, t_xmax;
 t_xmin │ t_xmax │                      string_agg                      
────────┼────────┼──────────────────────────────────────────────────────
   2699 │   2700 │ HEAP_XMIN_COMMITTED, HEAP_XMAX_COMMITTED
   2700 │   2702 │ HEAP_XMIN_COMMITTED, HEAP_XMAX_INVALID, HEAP_UPDATED
   2702 │      0 │ HEAP_XMIN_INVALID, HEAP_XMAX_INVALID, HEAP_UPDATED
Lo que entiendo de lo anterior es que la primera versión cobró vida con la transacción 2699, luego se reemplazó con éxito por la nueva versión a las 2700. 
Luego, la siguiente, que estaba viva desde 2700, tuvo un intento de UPDATEreversión en 2702, visto desde HEAP_XMAX_INVALID. 
El último nunca nació realmente, como lo demuestra HEAP_XMIN_INVALID.
Entonces, adivinando lo anterior, el primer y el último caso son obvios: ya no son visibles para la transacción 2703 o superior. 
El segundo tiene que buscarse en alguna parte, supongo que es el registro de confirmación, también conocido como clog.  
Para complicar aún más los problemas, un UPDATEresultado posterior en lo siguiente:
 t_xmin │ t_xmax │                     string_agg                     
────────┼────────┼────────────────────────────────────────────────────
   2699 │   2700 │ HEAP_XMIN_COMMITTED, HEAP_XMAX_COMMITTED
   2702 │      0 │ HEAP_XMIN_INVALID, HEAP_XMAX_INVALID, HEAP_UPDATED
   2703 │      0 │ HEAP_XMAX_INVALID, HEAP_UPDATED
   2700 │   2703 │ HEAP_XMIN_COMMITTED, HEAP_UPDATED
Aquí ya veo dos candidatos que podrían ser visibles. Entonces, finalmente, aquí están mis preguntas:
- ¿Es mi suposición de que 
cloges el lugar para mirar para determinar la visibilidad en estos casos? - ¿Qué banderas (o combinación de banderas) le dicen al sistema que visite 
clog? - ¿Hay alguna manera de examinar lo que hay dentro del 
clog? Hay menciones sobre laclogcorrupción en versiones anteriores de Postgres y una pista de que uno puede construir un archivo falso manualmente. Esta información ayudaría mucho con ella. 
fuente
