En noviembre del 2012 asistí al PgDay en Buenos Aires. Ahí presente la charla “Autovacuum, ¿bendición o maldición? Afrontando el reto”. En uno de los puntos de la charla explique, o al menos eso trate, que es necesario tratar de prevenir que el autovacuum ejecute VACUUM FREEZE.
El problema con VACUUM FREEZE ejecutado por el autovacuum es que leerá y escribirá toda la tabla y las probabilidades son que el autovacuum decida hacer esto en un momento de alta actividad. Durante la charla entonces explique que podemos tratar de adelantarnos al autovacuum chequeando el valor del campo relfrozenxid en la tabla de sistema pg_class, ahora agregare que la consulta es similar a: select relname, age(relfrozenxid) from pg_class where relkind = ‘r’ order by 2 desc;
En todo caso, como era de esperarse, surgió la pregunta: ¿qué contiene el campo relfrozenxid? A lo que yo respondi: “Básicamente, indica cual es el xid (id de transacción) mas bajo que podría encontrar en una tabla”. Claro, estaba simplificando un poco las cosas, y como no recordaba la definición exacta del campo no pensaba ahondar mas en ese tema. Además mi respuesta fue tan exacta como necesitaba serlo.
Excepto que luego de terminar la charla alguien me abordo y me dijo que aunque la charla había sido buena, me había equivocado sobre relfrozenxid pues supuestamente ese campo contenía el xid del último VACUUM FREEZE, y para probarlo el corrió un VACUUM FREEZE en una tabla y claro el campo fue actualizado al valor del xid que ejecuto ese VACUUM FREEZE. En ese momento ofrecí un artículo de blog aclarando el punto, pues yo sabía que yo tenía la razón aunque la prueba inmediata decía lo contrario. Y si se preguntan porque no lo aclare en ese momento: estaba en otro país, quería pasear.
Han pasado casi 8 meses y recién tengo tiempo y estoy de animo de escribir. Así que aquí está; mas vale tarde que nunca, ¿verdad?
Antes que nada me mantengo en mi afirmación: “Básicamente, indica cual es el xid (id de transacción) mas bajo que podría encontrar en una tabla” (simplificando).
Para probarlo crearemos una tabla t1(i int). Abriremos 3 sesiones y ejecutaremos “select txid_current();” en cada sesión para saber por cual id de transacción vamos, en mi caso las sesiones dieron los siguientes valores: 781, 782, 783. Luego abra 2 transacciones (en dos de las sesiones que abrimos previamente) y ejecute “select txid_current();” en cada una para asegurarse que la transacción consuma un id de transacción (784 y 785, en este caso). Entonces en la transaccion que se abrio último (785) ejecute: “insert into t1 select generate_series(1, 5);” y “commit;”, eso insertará 5 registros en la tabla t1 y cerrará una de las transacciones que abrimos y la otra quedará abierta (se cerró la transacción 785 y permanece abierta la 784).
Finalmente, en la tercera sesión que habíamos abierto, ejecute “select txid_current();” (que dará como resultado 786) seguido por “VACUUM FREEZE t1;” (que debería haber sido ejecutado en una nueva transacción por lo que debería tener 787 según la premisa de quien dijo que me había equivocado) y podemos consultar entonces “select relname, relfrozenxid from pg_class where relname = ‘t1’;” y encontraremos que en realidad el campo tiene: 784 (recuerden que el resultado que les dará es distinto pero que en esencia tendrán un valor menor al que se supone le corresponde al id de transacción del VACUUM FREEZE.
¿Por qué paso esto? simple, la transacción que dejamos abierta (la 784) necesita saber si los registros que la transacción 785 grabó son visibles para el o no y para esto necesita saber que transacción grabó esos registros y si esa transacción termino exitosamente. Debido a esto el VACUUM FREEZE no afecta los registros que podrían no ser visibles por alguna transacción, y el valor que se guarda en relfrozenxid corresponde al de la transacción mas antigua que este corriendo o al xmin de la tupla más vieja que podría no ser visible por dicha transacción. En todo caso, en la tabla no encontraré ninguna tupla con xmin inferior a relfrozenxid (expecto 2 y esto es la simplificación de la que hable antes).
Así que mi afirmación se mantiene, relfrozenxid “indica cual es el xid (id de transacción) mas bajo que podría encontrar en una tabla”.
A estas alturas quizá ya se estén preguntando que es exactamente lo que hace VACUUM FREEZE, pero no les recomiendo que esperen otro artículo hablando del tema… podrían pasar otros 8 meses hasta que me anime a escribirlo 😉