@ -397,8 +397,12 @@
<para>
<para>
The reason that periodic vacuuming solves the problem is that
The reason that periodic vacuuming solves the problem is that
<productname>PostgreSQL</productname> reserves a special XID
<command>VACUUM</> will mark rows as <emphasis>frozen</>, indicating that
as <literal>FrozenXID</>. This XID does not follow the normal XID
they were inserted by a transaction which committed sufficiently far in
the past that the effects of the inserting transaction is certain to be
visible, from an MVCC perspective, to all current and future transactions.
<productname>PostgreSQL</> reserves a special XID,
<literal>FrozenTransactionId</>, which does not follow the normal XID
comparison rules and is always considered older
comparison rules and is always considered older
than every normal XID. Normal XIDs are
than every normal XID. Normal XIDs are
compared using modulo-2<superscript>32</> arithmetic. This means
compared using modulo-2<superscript>32</> arithmetic. This means
@ -410,20 +414,19 @@
the next two billion transactions, no matter which normal XID we are
the next two billion transactions, no matter which normal XID we are
talking about. If the row version still exists after more than two billion
talking about. If the row version still exists after more than two billion
transactions, it will suddenly appear to be in the future. To
transactions, it will suddenly appear to be in the future. To
prevent this, old row versions must be reassigned the XID
prevent this, frozen row versions are treated as if the inserting XID were
<literal>FrozenXID</> sometime before they reach the
<literal>FrozenTransactionId</>, so that they will appear to be
two-billion-transactions-old mark. Once they are assigned this
<quote>in the past</> to all normal transactions regardless of wraparound
special XID, they will appear to be <quote>in the past</> to all
issues, and so such row versions will be valid until deleted, no matter
normal transactions regardless of wraparound issues, and so such
how long that is.
row versions will be valid until deleted, no matter how long that is.
This reassignment of old XIDs is handled by <command>VACUUM</>.
</para>
</para>
<para>
<para>
<xref linkend="guc-vacuum-freeze-min-age">
<xref linkend="guc-vacuum-freeze-min-age">
controls how old an XID value has to be before it's replaced with
controls how old an XID value has to be before its row version will be
<literal>FrozenXID</>. Larger values of this setting
frozen. Increasing this setting may avoid unnecessary work if the
preserve transactional information longer, while smaller values increase
rows that would otherwise be frozen will soon be modified again,
but decreasing this setting increases
the number of transactions that can elapse before the table must be
the number of transactions that can elapse before the table must be
vacuumed again.
vacuumed again.
</para>
</para>
@ -431,8 +434,8 @@
<para>
<para>
<command>VACUUM</> normally skips pages that don't have any dead row
<command>VACUUM</> normally skips pages that don't have any dead row
versions, but those pages might still have row versions with old XID
versions, but those pages might still have row versions with old XID
values. To ensure all old XIDs have been replaced by
values. To ensure all old row versions have been frozen, a
<literal>FrozenXID</>, a scan of the whole table is needed.
scan of the whole table is needed.
<xref linkend="guc-vacuum-freeze-table-age"> controls when
<xref linkend="guc-vacuum-freeze-table-age"> controls when
<command>VACUUM</> does that: a whole table sweep is forced if
<command>VACUUM</> does that: a whole table sweep is forced if
the table hasn't been fully scanned for <varname>vacuum_freeze_table_age</>
the table hasn't been fully scanned for <varname>vacuum_freeze_table_age</>
@ -447,8 +450,8 @@
the time <command>VACUUM</> last scanned the whole table. If it were to go
the time <command>VACUUM</> last scanned the whole table. If it were to go
unvacuumed for longer than
unvacuumed for longer than
that, data loss could result. To ensure that this does not happen,
that, data loss could result. To ensure that this does not happen,
autovacuum is invoked on any table that might contain XIDs older than the
autovacuum is invoked on any table that might contain unfrozen rows with
age specified by the configuration parameter <xref
XIDs older than the age specified by the configuration parameter <xref
linkend="guc-autovacuum-freeze-max-age">. (This will happen even if
linkend="guc-autovacuum-freeze-max-age">. (This will happen even if
autovacuum is disabled.)
autovacuum is disabled.)
</para>
</para>
@ -504,30 +507,25 @@
<para>
<para>
One disadvantage of decreasing <varname>vacuum_freeze_min_age</> is that
One disadvantage of decreasing <varname>vacuum_freeze_min_age</> is that
it might cause <command>VACUUM</> to do useless work: changing a table row's
it might cause <command>VACUUM</> to do useless work: freezing a row
XID to <literal>FrozenXID</> is a waste of time if the row is modified
version is a waste of time if the row is modified
soon thereafter (causing it to acquire a new XID). So the setting should
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
be large enough that rows are not frozen until they are unlikely to change
any more. Another disadvantage of decreasing this setting is
any more.
that details about exactly which transaction inserted or modified a
row will be lost sooner. This information sometimes comes in handy,
particularly when trying to analyze what went wrong after a database
failure. For these two reasons, decreasing this setting is not
recommended except for completely static tables.
</para>
</para>
<para>
<para>
To track the age of the oldest XIDs in a database,
To track the age of the oldest unfrozen XIDs in a database,
<command>VACUUM</> stores XID
<command>VACUUM</> stores XID
statistics in the system tables <structname>pg_class</> and
statistics in the system tables <structname>pg_class</> and
<structname>pg_database</>. In particular,
<structname>pg_database</>. In particular,
the <structfield>relfrozenxid</> column of a table's
the <structfield>relfrozenxid</> column of a table's
<structname>pg_class</> row contains the freeze cutoff XID that was used
<structname>pg_class</> row contains the freeze cutoff XID that was used
by the last whole-table <command>VACUUM</> for that table. All normal
by the last whole-table <command>VACUUM</> for that table. All rows
XIDs older than this cutoff XID are guaranteed to have been replaced by
inserted by transactions with XIDs XIDs older than this cutoff XID are
<literal>FrozenXID</> within the table . Similarly,
guaranteed to have been frozen . Similarly,
the <structfield>datfrozenxid</> column of a database's
the <structfield>datfrozenxid</> column of a database's
<structname>pg_database</> row is a lower bound on the normal XIDs
<structname>pg_database</> row is a lower bound on the unfrozen XIDs
appearing in that database — it is just the minimum of the
appearing in that database — it is just the minimum of the
per-table <structfield>relfrozenxid</> values within the database.
per-table <structfield>relfrozenxid</> values within the database.
A convenient way to
A convenient way to