gap so that
a regularly scheduled <command>VACUUM</command> or an autovacuum triggered by
normal delete and update activity is run in that window. Setting it too
close could lead to anti-wraparound autovacuums, even though the table
was recently vacuumed to reclaim space, whereas lower values lead to more
frequent aggressive vacuuming.
</para>
<para>
The sole disadvantage of increasing <varname>autovacuum_freeze_max_age</varname>
(and <varname>vacuum_freeze_table_age</varname> along with it) is that
the <filename>pg_xact</filename> and <filename>pg_commit_ts</filename>
subdirectories of the database cluster will take more space, because it
must store the commit status and (if <varname>track_commit_timestamp</varname> is
enabled) timestamp of all transactions back to
the <varname>autovacuum_freeze_max_age</varname> horizon. The commit status uses
two bits per transaction, so if
<varname>autovacuum_freeze_max_age</varname> is set to its maximum allowed value
of two billion, <filename>pg_xact</filename> can be expected to grow to about half
a gigabyte and <filename>pg_commit_ts</filename> to about 20GB. If this
is trivial compared to your total database size,
setting <varname>autovacuum_freeze_max_age</varname> to its maximum allowed value
is recommended. Otherwise, set it depending on what you are willing to
allow for <filename>pg_xact</filename> and <filename>pg_commit_ts</filename> storage.
(The default, 200 million transactions, translates to about 50MB
of <filename>pg_xact</filename> storage and about 2GB of <filename>pg_commit_ts</filename>
storage.)
</para>
<para>
One disadvantage of decreasing <varname>vacuum_freeze_min_age</varname> is that
it might cause <command>VACUUM</command> to do useless work: freezing a row
version is a waste of time if the row is modified
soon thereafter (causing it to acquire a new XID). So the setting should
be large enough that rows are not frozen until they are unlikely to change
any more.
</para>
<para>
To track the age of the oldest unfrozen XIDs in a database,
<command>VACUUM</command> stores XID
statistics in the system tables <structname>pg_class</structname> and
<structname>pg_database</structname>. In particular,
the <structfield>relfrozenxid</structfield> column of a table's
<structname>pg_class</structname> row contains the oldest remaining unfrozen
XID at the end of the most recent <command>VACUUM</command> that successfully
advanced <structfield>relfrozenxid</structfield> (typically the most recent
aggressive VACUUM). Similarly, the
<structfield>datfrozenxid</structfield> column of a database's
<structname>pg_database</structname> row is a lower bound on the unfrozen XIDs
appearing in that database — it is just the minimum of the
per-table <structfield>relfrozenxid</structfield> values within the database.
A convenient way to
examine this information is to execute queries such as:
<programlisting>
SELECT c.oid::regclass as table_name,
greatest(age(c.relfrozenxid),age(t.relfrozenxid)) as age
FROM pg_class c
LEFT JOIN pg_class t ON c.reltoastrelid = t.oid
WHERE c.relkind IN ('r', 'm');
SELECT datname, age(datfrozenxid) FROM pg_database;
</programlisting>
The <literal>age</literal> column measures the number of transactions from the
cutoff XID to the current transaction's XID.
</para>
<tip>
<para>
When the <command>VACUUM</command> command's <literal>VERBOSE</literal>
parameter is specified, <command>VACUUM</command> prints various
statistics about the table. This includes information about how
<structfield>relfrozenxid</structfield> and
<structfield>relminmxid</structfield> advanced, and the number of
newly frozen pages. The same details appear in the server log when
autovacuum logging (controlled by <xref