Improve documentation about MVCC-unsafe utility commands.

The table-rewriting forms of ALTER TABLE are MVCC-unsafe, in much the same
way as TRUNCATE, because they replace all rows of the table with newly-made
rows with a new xmin.  (Ideally, concurrent transactions with old snapshots
would continue to see the old table contents, but the data is not there
anymore --- and if it were there, it would be inconsistent with the table's
updated rowtype, so there would be serious implementation problems to fix.)
This was nowhere documented though, and the problem was only documented for
TRUNCATE in a note in the TRUNCATE reference page.  Create a new "Caveats"
section in the MVCC chapter that can be home to this and other limitations
on serializable consistency.

In passing, fix a mistaken statement that VACUUM and CLUSTER would reclaim
space occupied by a dropped column.  They don't reconstruct existing tuples
so they couldn't do that.

Back-patch to all supported branches.
This commit is contained in:
Tom Lane 2015-08-15 13:30:16 -04:00
parent 1f6a7eba46
commit 656363d839
3 changed files with 52 additions and 38 deletions

View File

@ -757,20 +757,6 @@ ERROR: could not serialize access due to read/write dependencies among transact
</listitem> </listitem>
</itemizedlist> </itemizedlist>
</para> </para>
<warning>
<para>
Support for the Serializable transaction isolation level has not yet
been added to Hot Standby replication targets (described in
<xref linkend="hot-standby">). The strictest isolation level currently
supported in hot standby mode is Repeatable Read. While performing all
permanent database writes within Serializable transactions on the
master will ensure that all standbys will eventually reach a consistent
state, a Repeatable Read transaction run on the standby can sometimes
see a transient state which is inconsistent with any serial execution
of serializable transactions on the master.
</para>
</warning>
</sect2> </sect2>
</sect1> </sect1>
@ -1667,6 +1653,38 @@ SELECT pg_advisory_lock(q.id) FROM
</sect2> </sect2>
</sect1> </sect1>
<sect1 id="mvcc-caveats">
<title>Caveats</title>
<para>
Some DDL commands, currently only <xref linkend="sql-truncate"> and the
table-rewriting forms of <xref linkend="sql-altertable">, are not
MVCC-safe. This means that after the truncation or rewrite commits, the
table will appear empty to concurrent transactions, if they are using a
snapshot taken before the DDL command committed. This will only be an
issue for a transaction that did not access the table in question
before the DDL command started &mdash; any transaction that has done so
would hold at least an <literal>ACCESS SHARE</literal> table lock,
which would block the DDL command until that transaction completes.
So these commands will not cause any apparent inconsistency in the
table contents for successive queries on the target table, but they
could cause visible inconsistency between the contents of the target
table and other tables in the database.
</para>
<para>
Support for the Serializable transaction isolation level has not yet
been added to Hot Standby replication targets (described in
<xref linkend="hot-standby">). The strictest isolation level currently
supported in hot standby mode is Repeatable Read. While performing all
permanent database writes within Serializable transactions on the
master will ensure that all standbys will eventually reach a consistent
state, a Repeatable Read transaction run on the standby can sometimes
see a transient state that is inconsistent with any serial execution
of the transactions on the master.
</para>
</sect1>
<sect1 id="locking-indexes"> <sect1 id="locking-indexes">
<title>Locking and Indexes</title> <title>Locking and Indexes</title>

View File

@ -646,7 +646,7 @@ ALTER TABLE ALL IN TABLESPACE <replaceable class="PARAMETER">name</replaceable>
This form changes the information which is written to the write-ahead log This form changes the information which is written to the write-ahead log
to identify rows which are updated or deleted. This option has no effect to identify rows which are updated or deleted. This option has no effect
except when logical replication is in use. <literal>DEFAULT</> except when logical replication is in use. <literal>DEFAULT</>
(the default for non-system tables) records the (the default for non-system tables) records the
old values of the columns of the primary key, if any. <literal>USING INDEX</> old values of the columns of the primary key, if any. <literal>USING INDEX</>
records the old values of the columns covered by the named index, which records the old values of the columns covered by the named index, which
must be unique, not partial, not deferrable, and include only columns marked must be unique, not partial, not deferrable, and include only columns marked
@ -948,7 +948,8 @@ ALTER TABLE ALL IN TABLESPACE <replaceable class="PARAMETER">name</replaceable>
<para> <para>
Adding a <literal>CHECK</> or <literal>NOT NULL</> constraint requires Adding a <literal>CHECK</> or <literal>NOT NULL</> constraint requires
scanning the table to verify that existing rows meet the constraint. scanning the table to verify that existing rows meet the constraint,
but does not require a table rewrite.
</para> </para>
<para> <para>
@ -970,11 +971,17 @@ ALTER TABLE ALL IN TABLESPACE <replaceable class="PARAMETER">name</replaceable>
</para> </para>
<para> <para>
To force an immediate rewrite of the table, you can use To force immediate reclamation of space occupied by a dropped column,
<link linkend="SQL-VACUUM">VACUUM FULL</>, <xref linkend="SQL-CLUSTER"> you can execute one of the forms of <command>ALTER TABLE</> that
or one of the forms of ALTER TABLE that forces a rewrite. This results in performs a rewrite of the whole table. This results in reconstructing
no semantically-visible change in the table, but gets rid of each row with the dropped column replaced by a null value.
no-longer-useful data. </para>
<para>
The rewriting forms of <command>ALTER TABLE</> are not MVCC-safe.
After a table rewrite, the table will appear empty to concurrent
transactions, if they are using a snapshot taken before the rewrite
occurred. See <xref linkend="mvcc-caveats"> for more details.
</para> </para>
<para> <para>

View File

@ -140,23 +140,12 @@ TRUNCATE [ TABLE ] [ ONLY ] <replaceable class="PARAMETER">name</replaceable> [
that were added due to cascading). that were added due to cascading).
</para> </para>
<warning> <para>
<para> <command>TRUNCATE</> is not MVCC-safe. After truncation, the table will
<command>TRUNCATE</> is not MVCC-safe (see <xref linkend="mvcc"> appear empty to concurrent transactions, if they are using a snapshot
for general information about MVCC). After truncation, the table taken before the truncation occurred.
will appear empty to all concurrent transactions, even if they See <xref linkend="mvcc-caveats"> for more details.
are using a snapshot taken before the truncation occurred. This </para>
will only be an issue for a transaction that did not access the
truncated table before the truncation happened &mdash; any
transaction that has done so would hold at least an
<literal>ACCESS SHARE</literal> lock, which would block
<command>TRUNCATE</> until that transaction completes. So
truncation will not cause any apparent inconsistency in the table
contents for successive queries on the same table, but it could
cause visible inconsistency between the contents of the truncated
table and other tables in the database.
</para>
</warning>
<para> <para>
<command>TRUNCATE</> is transaction-safe with respect to the data <command>TRUNCATE</> is transaction-safe with respect to the data