Waiting for 9.5 – Implement ALTER TABLE .. SET LOGGED / UNLOGGED

On 22nd of August, Alvaro Herrera committed patch:

Implement ALTER TABLE .. SET LOGGED / UNLOGGED
 
This enables changing permanent (logged) tables to unlogged and
vice-versa.
 
(Docs for ALTER TABLE / SET TABLESPACE got shuffled in an order that
hopefully makes more sense than the original.)
 
Author: Fabrízio de Royes Mello
Reviewed by: Christoph Berg, Andres Freund, Thom Brown
Some tweaking by Álvaro Herrera

In 9.1 we got unlogged tables. To summarize – these are tables that are much faster for writes, but are designed to lose all data in case of server failure.

That means – if you'll stop pg and start it properly – data will be there, but if you'll do “immediate stop", or you'll lose power, or pg will get “kill -9″‘ed – all the data is gone.

One of side effects of these tables were that they were not replicated (via WAL) – well, no log, nothing to replicate.

Now, with 9.5, we'll get ability to switch state of table – logged/unlogged.

It's not free (by far), but it's there.

How does it work? That's simple:

$ CREATE unlogged TABLE test (a int4);
CREATE TABLE
 
$ \d test
 Unlogged TABLE "public.test"
 COLUMN |  TYPE   | Modifiers 
--------+---------+-----------
 a      | INTEGER |

And now:

$ ALTER TABLE test SET logged;
ALTER TABLE
 
$ \d test
     TABLE "public.test"
 COLUMN |  TYPE   | Modifiers 
--------+---------+-----------
 a      | INTEGER |

and of course, I can do the same, the other way around:

$ ALTER TABLE test SET unlogged;
ALTER TABLE
 
$ \d test
 Unlogged TABLE "public.test"
 COLUMN |  TYPE   | Modifiers 
--------+---------+-----------
 a      | INTEGER |

It's nice, but there is one significant issue, or more specifically – a thing you should know about.

Let's see some details:

$ ALTER TABLE test ADD PRIMARY KEY (a);
ALTER TABLE
 
$ SELECT relname, relkind, relpersistence, relfilenode FROM pg_class WHERE relname IN ('test', 'test_pkey');
  relname  | relkind | relpersistence | relfilenode 
-----------+---------+----------------+-------------
 test      | r       | u              |       18067
 test_pkey | i       | u              |       18070
(2 ROWS)

and now, let's make it logged:

$ ALTER TABLE test SET logged;
ALTER TABLE
 
$ SELECT relname, relkind, relpersistence, relfilenode FROM pg_class WHERE relname IN ('test', 'test_pkey');
  relname  | relkind | relpersistence | relfilenode 
-----------+---------+----------------+-------------
 test      | r       | p              |       18075
 test_pkey | i       | p              |       18078
(2 ROWS)

relpersistence column has information whether it's logged ( relpersistence = ‘p' ) or not (relpersistence = ‘u').

But please note the relfilenode – it has changed.

Reason is very simple – changing logged state requires rewrite of the table. During this time the table is exclusively locked.

So, while it might be solution to certain cases, I think generally some caution will have to be applied to avoid locking application out of use.

In any way – it's a step in right direction (more power), so I'm very happy with it. Thanks guys.